PythonStudy——多路复用IO select实现

# 服务端代码
import socket
import select


server = socket.socket()
server.bind(("127.0.0.1", 1688))
server.listen(5)

# server.setblocking(False)

rlist = [server, ]  # 将需要检测(是否可读==recv)的socket对象放到该列表中
# accept也是一个读数据操作,默认也会阻塞  也需要让select来检测

# 注意 select最多能检测1024个socket 超出直接报错    这是select自身设计的问题    最终的解决方案epoll

wlist = []  # 将需要检测(是否可写==send)的socket对象放到该列表中
# 只要缓冲区不满都可以写

msgs = [("socket", "msg")]  # 存储需要发送的数据  等待select 检测后 在进行发送

print("start")
while True:
    readable_list, writeable_list, _ = select.select(rlist, wlist, [])  # 会阻塞等到 有一个或多个socket 可以被处理
    print("%s个socket可读" % len(readable_list), "%s个socket可写" % len(writeable_list))

    """
    readable_list 中存储的是已经可以读取数据的socket对象   可能是服务器 可能是客户端
    """
    # 处理可读列表
    for soc in readable_list:
        if soc == server:
            # 服务器的处理
            client, addr = server.accept()
            # 将新连接的socket对象 加入到待检测列表中
            rlist.append(client)
        else:
            try:
                # 客户端的处理
                data = soc.recv(2048)
                if not data:
                    soc.close()
                    rlist.remove(soc)  # 如果对方下线  关闭socket 并且从待检测列表中删除
                    continue
                # 不能直接发  因为此时缓冲区可能已经满了    导致send阻塞住, 所以要发送数据前一个先这个socket交给select来检查
                # soc.send(data.upper())
                if soc not in wlist:
                    wlist.append(soc)
                # 将要发送的数据先存起来
                msgs.append((soc, data))
            except ConnectionResetError:
                soc.close()
                # 对方下线后 应该从待检测列表中删除 socket
                rlist.remove(soc)
                wlist.remove(soc)
    # 处理可写列表
    for soc in writeable_list:
        # 由于一个客户端可能有多个数据要发送 所以遍历所有客户端
        for i in msgs[:]:
            if i[0] == soc:
                soc.send(i[1])
                # 发送成功  将这个数据从列表中删除
                msgs.remove(i)
        # 数据已经都发给客户端   这个socket还需不需要检测是否可写,必须要删除
        wlist.remove(soc)  # 否则 只要缓冲区不满 一直处于可写 导致死循环
# 客户端代码
import socket

client = socket.socket()
client.connect(("127.0.0.1",1688))
原文地址:https://www.cnblogs.com/tingguoguoyo/p/10999804.html