程序员

python 多路复用IO select服务器模型 epoll服

2018-12-15  本文已影响2人  L_Leisure

python 的select服务器模型

python提供了操作系统底层select接口的封装版本,使用起来会更加方便。

select(rlist, wlist, xlist[, timeout]) -> (rlist, wlist, xlist)

rlist wlist xlist都是列表数据结构。返回的列表则是对应的可读表,可写表,有异常表。

import select
from socket import *


def main():
    # 1. 创建socket套接字
    tcp_server = socket(AF_INET, SOCK_STREAM)
    # 2. 绑定IP地址和端口
    tcp_server.bind(("", 6699))
    # 3. 把主动模式变成被动模式 只能接收 不能发送数据
    tcp_server.listen(5)
    # 4. 声明一个列表
    inputs_list = [tcp_server]
    while True:
        # 阻塞在这里,内核监听inputs_list里的套接字,如果状态改变就进行解阻塞, 并返回有变化的套接字
        read_list, _, _ = select.select(inputs_list, [], [])
        # 循环read_list
        for sock in read_list:
            # 判断是不是被动的套接字
            if sock == tcp_server:
                # 创建新的套接字
                new_socket, client_info = sock.accept()
                # 将创建好的套接字添加到列表中
                inputs_list.append(new_socket)
                print(f"连接到{client_info}")
            else:
                # 接收数据
                raw_data = sock.recv(1024)
                if raw_data:
                    # 发送数据
                    sock.send(raw_data)
                    print(f"收到{client_info}的数据{raw_data.decode('gb2312')}")
                else:
                    # 断开连接
                    sock.close()
                    # 将套接字从列表中移除
                    inputs_list.remove(sock)


if __name__ == '__main__':
    main()

  1. 32系统只能1024个连接 64位 2048个

    2.采用轮询机制,当并发大的时候,就会崩了

​ POLL只是突破了连接的限制

python 的epoll服务器模型

为了解决select和poll轮询机制的效率问题,从Linux2.6内核开始,引入了epoll接口。

没有最大并发连接的限制,能打开的文件描述符的上限远大于1024。

效率提升,不是轮询的方式,而是采用了事件通知机制,当文件描述符配置为epoll方式后,一旦事件发生,设备驱动会主动通知内核,此时应用空间会得到通知。

应用空间的处理机制几乎不变,主要是内核结构的修改。

from socket import *
import select


def main():
    # 创建socket套接字
    tcp_server = socket(AF_INET, SOCK_STREAM)
    # 重复使用绑定的信息
    tcp_server.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
    # 绑定端口,ip
    tcp_server.bind(("", 6699))
    # 把主动模式变为被动模式,只能接收,不能发送数据
    tcp_server.listen(5)
    # 创建epoll()对象
    epoll = select.epoll()
    # 将被动套接字添加到epoll对象中
    print(f"被动套接字:{tcp_server.fileno()}")
    epoll.register(tcp_server.fileno(), select.EPOLLIN)
    # 声明一个字典,用来存储新的套接字
    new_sockets = {}
    # 声明一个字典,用来存储客户端信息
    client_infos = {}
    while True:
        print(f"所有新的套接字{new_sockets}")
        print(f"所有客户端信息{client_infos}")
        # 阻塞在这里,等待套接字状态改变
        epoll_list = epoll.poll()
        print(f"epoll_list:{epoll_list}")
        # 循环epoll_list
        for fd, events in epoll_list:
            print(f"fd:{fd},events:{events}")
            # 判断fd是不是被动套接字
            if fd == tcp_server.fileno():
                # 创建新的套接字
                new_socket, client_info = tcp_server.accept()
                print(f"连接到{new_socket}")
                # 将新的套接字接入到epoll监听列表
                epoll.register(new_socket.fileno(), select.EPOLLIN)
                # 将新的套接字存入字典
                new_sockets[new_socket.fileno()] = new_socket
                # 将新的客户端存入字典
                client_infos[new_socket.fileno()] = client_info
            else:
                # 接收信息
                raw_data = new_sockets[fd].recv(1024)
                # 判断
                if raw_data:
                    print(f"收到{client_infos[fd]}的数据{raw_data.decode('gb2312')}")
                else:
                    # 关闭套接字
                    new_sockets[fd].close()
                    # 注销监听队列
                    epoll.unregister(fd)
                    # 字典删除
                    del new_sockets[fd]
                    del client_infos[fd]


if __name__ == '__main__':
    main()

上一篇下一篇

猜你喜欢

热点阅读