异步select
server coding:
1 #!/usr/bin/python 2 # -*- coding: utf-8 -*- 3 4 import select 5 import socket 6 import sys 7 import Queue 8 9 # Create a TCP/IP socket 10 server = socket.socket(socket.AF_INET,socket.SOCK_STREAM) 11 server.setblocking(False) 12 13 # Bind the socket to the port 14 server_address = ('localhost',1000) 15 print >>sys.stderr, 'starting up on %s port %s'%server_address 16 server.bind(server_address) 17 18 # Listen for incoming connections 19 server.listen(5) 20 21 # Sockets from which we expect to read 22 inputs = [server] 23 24 # Sockets to which we expect to write 25 outputs = [] 26 27 # Outgoing message queues (socket:Queue) 28 message_queues = {} 29 30 while True: 31 # Wait for at least one of the sockets to be ready for processing 32 print >>sys.stderr, '\nwaiting for the next event' 33 #分别筛选出可接收消息的sockets、等待发送消息的sockets、和中途出错的sockets。 34 #其中exceptional为了把所有可接收消息的sockets都遍历到,所以要从inputs列表中读取。 35 readable, writable, exceptional = select.select(inputs,outputs,inputs) 36 37 # Handle inputs 38 for s in readable: 39 #第一种情况,创建一个待接收消息的socket放入inputs 40 if s is server: 41 # A "readable" server socket is ready to accept a connection 42 connection, client_address = s.accept() 43 print >>sys.stderr, 'new connection from', client_address 44 connection.setblocking(0) 45 inputs.append(connection) 46 47 # Give the connection a queue for data we want to send 48 message_queues[connection] = Queue.Queue() 49 50 #第二种情况,在后续循环中,已经添加到inputs中的sockets已经不是readable了,所以 51 #要进行接收消息,消息存在message_queues中,并把该socket添加到outputs。 52 else: 53 data = s.recv(1024) 54 if data: 55 # A readable client socket has data 56 print >>sys.stderr, 'receieved "%s" from %s'%(data.upper(),s.getpeername()) 57 message_queues[s].put(data) 58 # Add output channel for response,添加到待发送消息列表 59 if s not in outputs: 60 outputs.append(s) 61 62 #第三种情况就是这个客户端已经断开了, 63 #所以你再通过recv()接收到的数据就为空了, 64 #所以这个时候你就可以把这个跟客户端的连接关闭了。 65 else: 66 print >>sys.stderr, 'closing',client_address,'after reading no data' 67 if s in outputs: 68 outputs.remove(s)#既然客户端都断开了,我就不用再给它返回数据了,所以这时候如果这个客户端的连接对象还在outputs列表中,就把它删掉 69 inputs.remove(s)#inputs中也删除掉 70 s.close()#把这个连接关闭掉 71 72 # Remove message queue 73 del message_queues[s] 74 75 # Handle outputs 76 for s2 in writable: 77 try: 78 next_msg = message_queues[s2].get_nowait() 79 #没有消息了 80 except Queue.Empty: 81 # No messages waiting so stop checking for writability. 82 print >>sys.stderr,'output queue for',s2.getpeername(),'is empty' 83 outputs.remove(s2) 84 #发送消息 85 else: 86 print >>sys.stderr, 'sending "%s" to %s'%(next_msg,s2.getpeername()) 87 s2.send(next_msg) 88 89 # Handle "exceptional conditions" 90 for s3 in exceptional: 91 print >>sys.stderr, 'handling exceptional condition for ',s3.getpeername() 92 # Stop listening for input on the connection 93 inputs.remove(s3) 94 if s3 in outputs: 95 outputs.remove(s3) 96 s3.close() 97 98 #Remove message queue 99 del message_queues[s3] 100 101 102
client coding
1 # -*- coding: utf-8 -*- 2 """ 3 Created on Sun Oct 23 14:49:20 2016 4 5 @author: fuzzier 6 """ 7 8 import sys 9 import socket 10 11 messages = ['This is the message.', 12 'It will be sent', 13 'in parts.' 14 ] 15 server_address = ('localhost',1000) 16 17 # Create a TCP/IP socket,创建两个客户端 18 socks = [socket.socket(socket.AF_INET,socket.SOCK_STREAM), 19 socket.socket(socket.AF_INET,socket.SOCK_STREAM) 20 ] 21 22 # Connect the socket to the port where the server is listening 23 print >>sys.stderr, 'connecting to %s port %s'%server_address 24 for s in socks: 25 s.connect(server_address) 26 27 for message in messages: 28 29 # Send messages on both sockets 30 for s2 in socks: 31 print >>sys.stderr, '%s:sending "%s"'%(s2.getsockname(),message) 32 s2.send(message) 33 34 #Read responses on both sockets 35 for s3 in socks: 36 data = s3.recv(1024) 37 print >>sys.stderr, '%s: received "%s"' % (s3.getsockname(), data.upper()) 38 if not data: 39 print >>sys.stderr,'closing socket',s3.getsockname() 40 s3.close()
原理图:
运行结果: