关于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]