非阻塞套接字编程:
server端
import socket server = socket.socket() server.setblocking(False) server.bind(('', 8884)) server.listen(5) clients = [] while True: try: conn, addr = server.accept() conn.setblocking(False) except BlockingIOError: pass else: print(f'用户{addr[0]},建立了连接。') clients.append(conn)
all_conn_data = [conn for conn inn clients] # 迭代新列表,防止数据紊乱(避免在迭代对象的时候修改对象,造成数据紊乱) for conn in all_conn_data: try: res = conn.recv(1024) if res: print(res) else: conn.close() print(f'用户{addr[0]},断开了连接。') clients.remove(conn) except BlockingIOError: pass
all_conn_data = clients
IO多路复用之epoll(linux上效率最高的io复用技术)机制基于linux内核 : (tornado封装了epoll,因此tornado适用于linux)
IO多路复用(epoll)
注册事件
等待事件被触发
由操作系统监控
惰性 非主动调用
代码调用
import socket import selectors server = socket.socket() epoll_selector = selectors.EpollSelector() server.bind(('', 8888)) server.listen(5) def server_recv(conn): recv_data = conn.recv(1024) if recv_data: print(recv_data) conn.send(recv_data) else: epoll_selector.unregister(conn) conn.close() def server_conn(server): conn, addr = server.accept() epoll_selector.register(conn, selectors.EVENT_READ, server_recv) epoll_selector.register(server, selectors.EVENT_READ, server_conn) while True: events = epoll_selector.select() # print(events) #[(SelectorKey( # fileobj=<socket.socket fd=3, # family=AddressFamily.AF_INET, # type=SocketKind.SOCK_STREAM, # proto=0, laddr=('0.0.0.0', 8888)>, # fd=3, events=1, # data=<function server_conn at 0xb72c16ec>), 1)] for event, n in events: file_obj = event.fileobj # 套接字 callbanck = event.data callbanck(file_obj)