zoukankan      html  css  js  c++  java
  • 单进程-非阻塞服务器

    from socket import *
    #1.创建socket
    serSocket = socket(AF_INET, SOCK_STREAM)
    
    #2. 绑定本地ip以及port
    localAddr = ('', 7788)
    serSocket.bind(localAddr)
    
    #3. 让这个socket 变为非堵塞
    serSocket.setblocking(False)
    
    #4. 将socket变为监听(被动)套接字
    serSocket.listen(100)
    
    # 用来保存所有已经连接的客户端的信息
    clientAddrList = []
    
    while True:
    
        #等待一个新的客户端的到来(即完成3次握手的客户端)
        try:
            clientSocket,clientAddr = serSocket.accept()
        except:
            pass
        else:
            print("一个新的客户端到来:%s"%str(clientAddr))
            clientSocket.setblocking(False)
            clientAddrList.append((clientSocket,clientAddr))
    
        for clientSocket,clientAddr in clientAddrList:
            try:
                recvData = clientSocket.recv(1024)
            except:
                pass
            else:
                if len(recvData)>0:
                    print("%s:%s"%(str(clientAddr), recvData))
                else:
                    clientSocket.close()
                    clientAddrList.remove((clientSocket, clientAddr))
                    print("%s 已经下线"%str(clientAddr))

     select,轮询最多可监听1024个人,poll无默认值,但是也是轮询

    import select
    import socket
    import sys
    
    
    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server.bind(('', 7788))
    server.listen(5)
    
    inputs = [server, sys.stdin]
    
    running = True
    
    while True:
    
        # 调用 select 函数,阻塞等待
        readable, writeable, exceptional = select.select(inputs, [], [])
    
        # 数据抵达,循环
        for sock in readable:
    
            # 监听到有新的连接
            if sock == server:
                conn, addr = server.accept()
                # select 监听的socket
                inputs.append(conn)
    
            # 监听到键盘有输入
            elif sock == sys.stdin:
                cmd = sys.stdin.readline()
                running = False
                break
    
            # 有数据到达
            else:
                # 读取客户端连接发送的数据
                data = sock.recv(1024)
                if data:
                    sock.send(data)
                else:
                    # 移除select监听的socket
                    inputs.remove(sock)
                    sock.close()
    
        # 如果检测到用户输入敲击键盘,那么就退出
        if not running:
            break
    
    server.close()

     epoll非轮询,无限制,事件通知机制

    • EPOLLIN (可读)
    • EPOLLOUT (可写)
    • EPOLLET (ET模式)

    epoll对文件描述符的操作有两种模式:LT(level trigger)和ET(edge trigger)。LT模式是默认模式,LT模式与ET模式的区别如下:

    LT模式:当epoll检测到描述符事件发生并将此事件通知应用程序,应用程序可以不立即处理该事件。下次调用epoll时,会再次响应应用程序并通知此事件。
    
    ET模式:当epoll检测到描述符事件发生并将此事件通知应用程序,应用程序必须立即处理该事件。如果不处理,下次调用epoll时,不会再次响应应用程序并通知此事件。
    import socket
    import select
    
    # 创建套接字
    s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    
    # 设置可以重复使用绑定的信息
    s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
    
    # 绑定本机信息
    s.bind(("",7788))
    
    # 变为被动
    s.listen(10)
    
    # 创建一个epoll对象
    epoll=select.epoll()
    
    # 测试,用来打印套接字对应的文件描述符
    # print s.fileno()
    # print select.EPOLLIN|select.EPOLLET
    
    # 注册事件到epoll中
    # epoll.register(fd[, eventmask])
    # 注意,如果fd已经注册过,则会发生异常
    # 将创建的套接字添加到epoll的事件监听中
    epoll.register(s.fileno(),select.EPOLLIN|select.EPOLLET)
    
    
    connections = {}
    addresses = {}
    
    # 循环等待客户端的到来或者对方发送数据
    while True:
    
        # epoll 进行 fd 扫描的地方 -- 未指定超时时间则为阻塞等待
        epoll_list=epoll.poll()
    
        # 对事件进行判断
        for fd,events in epoll_list:
    
            # print fd
            # print events
    
            # 如果是socket创建的套接字被激活
            if fd == s.fileno():
                conn,addr=s.accept()
    
                print('有新的客户端到来%s'%str(addr))
    
                # 将 conn 和 addr 信息分别保存起来
                connections[conn.fileno()] = conn
                addresses[conn.fileno()] = addr
    
                # 向 epoll 中注册 连接 socket 的 可读 事件
                epoll.register(conn.fileno(), select.EPOLLIN | select.EPOLLET)
    
    
            elif events == select.EPOLLIN:
                # 从激活 fd 上接收
                recvData = connections[fd].recv(1024)
    
                if len(recvData)>0:
                    print('recv:%s'%recvData)
                else:
                    # 从 epoll 中移除该 连接 fd
                    epoll.unregister(fd)
    
                    # server 侧主动关闭该 连接 fd
                    connections[fd].close()
    
                    print("%s---offline---"%str(addresses[fd]))

     gevent协程服务器

    import sys
    import time
    import gevent
    
    from gevent import socket,monkey
    monkey.patch_all()
    
    def handle_request(conn):
        while True:
            data = conn.recv(1024)
            if not data:
                conn.close()
                break
            print("recv:", data)
            conn.send(data)
    
    
    def server(port):
        s = socket.socket()
        s.bind(('', port))
        s.listen(5)
        while True:
            cli, addr = s.accept()
            gevent.spawn(handle_request, cli)
    
    if __name__ == '__main__':
        server(7788)
  • 相关阅读:
    汉字在屏幕上的显示
    手机上的ROM与RAM
    数据表示和计算
    存储器的层次结构
    计算机系统概述
    Python中的文件路径的分隔符
    网络爬虫的基本原理
    iOS多线程简介
    Quartz2D简介
    iOS 事件传递响应链
  • 原文地址:https://www.cnblogs.com/Erick-L/p/7189519.html
Copyright © 2011-2022 走看看