# 服务端代码
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))