关于Socket中的Select使用理解
以下是代码和中文注释的个人理解
import socket, select, Queue
server=('192.168.2.100',10086)
#创建TCP/TP Socket
sock_ser=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#设置不阻塞监听
sock_ser.setblocking(False)
sock_ser.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
#绑定IP地址
sock_ser.bind(server)
#监听连接
sock_ser.listen(10)
#准备用来读取数据的Socket,客户端向服务端的读端口写
incomes=[sock_ser]
#准备用来写的Socket,客户端从写Socket读
outputs=[]
"""
写出消息的队列,由于select是循环机制,所以每个独立的outputs都需要一个队列来保存待写出的数据,
等到轮回到自己的时候写出
"""
msg_que={}
#超时时间。
timeout=20
#服务端的Socket用来接受服务端的连接,并用作与循环。
while incomes:
"""
先等待至少一个Socket的数据处理,Select返回当前三个列表。
这三个数据来自于可读,可写,返回的错误。
Select监听并等待网络活动。如果有网络活动则开始执行
"""
rs,ws,es=select.select(incomes,outputs,incomes,timeout)
if not(rs or ws or es):
print "error: timeout...."
break
for s in rs:
"""
此处的rs存储很多Socket,
开始存储只有服务端本身的Socket,用于与客户端建立新的连接。并将客户端建立好的连接存储在incomes中,incomes会返回给rs。
存储的的客户端,会被用于收发数据。
"""
#rs队列中按个读取,如果是服务端的socket就用那个与建立新的连接。
if s is sock_ser:
conn,addr=s.accept()
print "connect by ",addr
conn.setblocking(False)
incomes.append(conn)
#为接入的客户端提供一个队列来发送回复给客户端的数据
msg_que[conn]=Queue.Queue()
#如果不是服务端的socket,是客户端建立连接的Socket,就收数据,并判断是否断开。
else:
data=s.recv(1024)
#有数据就收数据
if data:
print "receive client ",data
msg_que[s].put(data)
if s not in outputs:
outputs.append(s)
#可读的socket没有数据发送,则说明客户端断开连接,我们删除这个客户端。
else:
if s in outputs:
outputs.remove(s)
incomes.remove(s)
s.close()
del msg_que[s]
#写操作,查看队列里面是否有东西,并发送到对应的Socket.
for s in ws:
try:
msg = msg_que[s].get_nowait()
except Queue.Empty:
#因为是轮回的,当前面连接断开后,写的socket尚未删除,这一步还是要执行的,所以最后输出了几个EMPTY。
print 'msg empty'
outputs.remove(s)
else:
s.send("from server :"+msg)
for s in es:
print "except",s.getpeername()
if s in incomes:
incomes.remove(s)
if s in outputs:
outputs.remove(s)
s.close()
del msg_que[s]