IO多路复用,简单理解就是一个客户端可以同时访问多个服务器端口,一个服务器也可以同时接受多个客户端的访问。
多路复用的方式有三种:select、pool、epoll,Windows只支持select方式。
select、pool内部使用的是for循环检测,select最多监听1024个、pool监听个数不限。epoll是异步方式,不使用循环监听,谁有变化的时候来通知我。
这里记录的是基于select实现IO多路复用:
一、一个客户端口、多个服务器端口;读写未分离
服务器端同时开放多个端口等待访问,循环监听各端口情况,当有服务器端口被访问时,建立连接并开始通信。
服务器端:
import socket import select # 服务器端口1:8088 sk1 = socket.socket() sk1.bind(('192.168.1.103',8088,)) sk1.listen(5) # 服务器端口2:8008 sk2 = socket.socket() sk2.bind(('192.168.1.103',8008,)) sk2.listen(5) # 服务器端口3:8080 sk3 = socket.socket() sk3.bind(('192.168.1.103',8080,)) sk3.listen(5) # 开放的服务器端句柄 inputs = [sk1,sk2,sk3,] outputs = [] time = 1 while True: # 循环监听各端口 # r_list:监听到的有变换的端口句柄 # w_list与outputs相对应,输入什么、输出什么。 # e_list:监听到的又异常或断开连接的端口句柄 # inputs:被监听的端口句柄列表 # time:监听一次的最长时间间隔 r_list , w_list , e_list = select.select(inputs,outputs,inputs,time) print('被监听的对象:%d个' % len(inputs)) # 循环处理被访问的端口 for sk in r_list: # 建立连接,创建连接句柄conn conn,address = sk.accept() # 发送欢迎消息至客户端 conn.sendall(bytes('hello...',encoding='utf-8')) # 接收服务的消息后关闭连接 response = conn.recv(1024) print(response) conn.close() # 删除对服务器端口的监听 inputs.remove(sk)
客户端:
import socket s1 = socket.socket() # 建立连接 s1.connect(('192.168.1.103',8008,)) while True: data = input('>>>') if data == 'q': break else: # 接收信息 response = str(s1.recv(1024),encoding='utf-8') print(response) # 发送消息 s1.sendall(bytes(data,encoding='utf-8')) # 切断连接 s1.close()
二、一个服务端口、多个客户端口;读写分离
使用for循环实现伪异步方式的IO多路复用,可同时处理多个客户端的访问请求、并建立连接开始通信。
服务器端:
import socket # 服务器端口开放 sk1 = socket.socket() sk1.bind(('192.168.1.103',8088,)) sk1.listen() import select inputs_or_conn = [sk1,] outputs = [] message_dict = {} while True: # 循环监听各端口 r_list,w_list,e_list = select.select(inputs_or_conn,outputs,inputs_or_conn,1) print('正在监听的对象:%d' % len(inputs_or_conn)) print(r_list) for sk in r_list: # 新用户访问 ,建立连接 if sk == sk1: conn,adress = sk.accept() # 登记并开始监听来访的socket inputs_or_conn.append(conn) # 创建列表,记录客户端发过来的信息 message_dict[conn] = [] # 已建立连接的用户继续访问 else: try: # 接收客户端发送的消息 data_bytes = sk.recv(1024) except Exception as ex: # 客户端出现异常或者退出,停止监听 inputs_or_conn.remove(sk) else: # 将消息str存入客户端消息列表 data_str = str(data_bytes,encoding='utf-8') message_dict[sk].append(data_str) # 客户添加至w_list等待反馈 w_list.append(sk) for conn in w_list: # 进行消息回复,回复后conn从w_list中删除 conn.sendall(bytes(message_dict[conn][0]+'hi...',encoding='utf-8')) w_list.remove(conn) # 将此消息从w_list中删除 del message_dict[conn][0]
客户端1:
import socket s1 = socket.socket() # 建立连接 s1.connect(('192.168.1.103',8008,)) while True: data = input('>>>') if data == 'q': break else: # 接收信息 response = str(s1.recv(1024),encoding='utf-8') print(response) # 发送消息 s1.sendall(bytes(data,encoding='utf-8')) # 切断连接 s1.close()
客户端2:
import socket s2 = socket.socket() # 建立连接 s2.connect(('192.168.1.103',8088,)) while True: data = input('>>>') if data == 'q': break else: # 发送消息 s2.sendall(bytes(data,encoding='utf-8')) # 接收信息 response = str(s2.recv(1024),encoding='utf-8') print(response) # 切断连接 s2.close()
浙公网安备 33010602011771号