select简单示例,有注释
Posted dsowasp
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了select简单示例,有注释相关的知识,希望对你有一定的参考价值。
全部都在代码中:
import select import socket import queue """ 简单的select 实现echo server 个人理解: select 编程思想,让select去去判断能不能读或能不能写。 如果能读或能写,select就会告知readable或writeable,这时就得让文件句柄去读或写, 在这里是scoket,recv()或scoket.send()去执行实际的操作 """ server = socket.socket() # 获取一个套接字 server.setblocking(False) # 设置为非阻塞模式 server.bind((‘127.0.0.1‘,9001)) # 绑定ip和端口 server.listen(5) # 启动监听,到这步可以在netstat 看到监听状态,如果没有server.accept()的话,客户端的连接会被拒绝 inputs = [ server ] # 设置输入队列,当server的监听收到客户端连接时,select会认为这个server为可读,就得让server.accpet()去接收客户端连接 # 或者当socket有新的数据发送过来时,select会认为这个socket是可读的,就得去让socket的recv()去接收数据 outputs = [] # 当socket可以发送数据给对端时,select会认定这个socket是 message_queue = {} # 消息队列,key值为socket套接字 n = 0 # 体现while循环了多少次 while inputs: # inputs中释放存在值 print("waiting for connect..., %s"%n) readable , writeable ,exceptions = select.select(inputs,outputs,inputs) # select就像一个非常强大的监视器,监视各个文件句柄的是否可读可写。 for s in readable: # 循环可读的。 if s is server: # 如果是select套接字 print("server can read...") conn, addr = s.accept() # 就接收客户端连接 print("welcome (%s,%s) to connect..."%addr) inputs.append(conn) # 将客户端套连接接字放入inputs,而不是马上接收或发生数据。 # s.setblocking(False) else: # 如果不是server套接字 try: data = s.recv(1024) # 就表明客户端连接套接字收到了客户端发送来的数据 except Exception as e: # 客户端进程被强制关闭,导致客户端发送rst包。 ConnectionResetError print(e) inputs.remove(s) # 如果客户端退出,就讲这个套接字从inputs中移除 if s in outputs: # 如果这个套接字存在于outputs中,也将这个套接字从outputs中移除,因为客户端都关闭了 # 还将这个套接字放在outputs中没有了,发不了数据了啊。 outputs.remove(s) s.close() # 记得关闭这个套接字 break # 这里要break,因为s.recv(1024)异常了,data根本就没有被定义,下面的if data就会报错。 if data: # 如果有数据 print("recv from %s:%s"%(s.getpeername(),data.decode())) message_queue[s] = queue.Queue() # 将收到的数据放入消息队列中 message_queue[s].put(data) outputs.append(s) # 因为是echo server,所有有道数据后就得原有返回数据,但是这里不立即返回,而是交由select. else: print("the client (%s,%s) is closed "%s.getpeername()) # 如果data为空,表示客户端正常关闭连接,客户端发送了fin. if s in outputs: # 客户端关闭了,这个套接字也就没必要放在outputs和inputs中了 outputs.remove(s) inputs.remove(s) del message_queue[s] # 消息队列也可以清除 s.close() # 关闭套接字 for s in writeable: # 如果可写,“好像ouputs有连接的套接字 存在就是可写的。” try: data = message_queue[s].get_nowait() # 获取要发送的消息 except queue.Empty: # 消息队列为空也是可写的。 print("outpt queue for (%s,%s) in empty"%s.getpeername()) outputs.remove(s) # 因为是echo server,所以消息队列为空时,说明已经回应了数据给对端,就不用一直去判断这个套接字是否可写了。 # s.close() # 没有数据可发送并不代表要关闭socket else: print("send data to client (%s,%s)"%s.getpeername()) s.send(data) outputs.remove(s) # 发送完数据后,其实可以将这个套接字从outputs中移除,因为是echo server嘛 for s in exceptions: # 如果发生错误 print("expect happend on (%s,%s)"%s.getpeername()) inputs.remove(s) # 将这个套接字从inouts,outputs中移除 if s in outputs: outputs.remove(s) s.close() # 连接要关闭 del message_queue[s] # 消息队列也要关闭 n += 1 # 看看while循环可多少次
1 """ 2 运行结果: 3 waiting for connect..., 0 4 server can read... 5 welcome (127.0.0.1,56348) to connect... 6 waiting for connect..., 1 7 recv from (‘127.0.0.1‘, 56348):the 1st client 8 waiting for connect..., 2 9 send data to client (127.0.0.1,56348) 10 waiting for connect..., 3 11 server can read... 12 welcome (127.0.0.1,56349) to connect... 13 waiting for connect..., 4 14 recv from (‘127.0.0.1‘, 56349):the 2th client 15 waiting for connect..., 5 16 send data to client (127.0.0.1,56349) 17 waiting for connect..., 6 18 recv from (‘127.0.0.1‘, 56349):2th will kill by os 19 waiting for connect..., 7 20 send data to client (127.0.0.1,56349) 21 waiting for connect..., 8 22 [WinError 10054] 远程主机强迫关闭了一个现有的连接。 23 waiting for connect..., 9 24 recv from (‘127.0.0.1‘, 56348):1st will s.close() close the socket 25 waiting for connect..., 10 26 send data to client (127.0.0.1,56348) 27 waiting for connect..., 11 28 the client (127.0.0.1,56348) is closed 29 waiting for connect..., 12 30 """
客户端:
import socket s = socket.socket() s.connect((‘127.0.0.1‘,9001)) while True: data = input(">> ").strip() if data == "": continue if data == "q": s.close() break s.send(bytes(data,encoding="utf-8")) data = s.recv(1024) print("recv:",data.decode())
以上是关于select简单示例,有注释的主要内容,如果未能解决你的问题,请参考以下文章