服务端:
importselect
importsocket
importsys
importQueue
# Create a TCP/IP socket
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setblocking(False)
# Bind the socket to the port
server_address = ('localhost',9999)
print(sys.stderr,'starting up on %s port %s'% server_address)
server.bind(server_address)
# Listen for incoming connections
server.listen(5)
# Sockets from which we expect to read
inputs = [server]
# Sockets to which we expect to write
outputs = []
message_queues = {}
whileinputs:
# Wait for at least one of the sockets to be ready for processing
print('\nwaiting for the next event')
readable, writable, exceptional = select.select(inputs, outputs, inputs)
# Handle inputs
forsinreadable:
ifsisserver:
# A "readable" server socket is ready to accept a connection
connection, client_address = s.accept()
print('new connection from', client_address)
connection.setblocking(False)
inputs.append(connection)
# Give the connection a queue for data we want to send
message_queues[connection] = Queue.Queue()
else:
data = s.recv(1024)
ifdata:
# A readable client socket has data
print(sys.stderr,'received "%s" from %s'% (data, s.getpeername()))
message_queues[s].put(data)
# Add output channel for response
ifsnot inoutputs:
outputs.append(s)
else:
# Interpret empty result as closed connection
print('closing', client_address,'after reading no data')
# Stop listening for input on the connection
ifsinoutputs:
outputs.remove(s)# 既然客户端都断开了,我就不用再给它返回数据了,所以这时候如果这个客户端的连接对象还在outputs列表中,就把它删掉
inputs.remove(s)# inputs中也删除掉
s.close()# 把这个连接关闭掉
# Remove message queue
delmessage_queues[s]
# Handle outputs
forsinwritable:
try:
next_msg = message_queues[s].get_nowait()
exceptQueue.Empty:
# No messages waiting so stop checking for writability.
print('output queue for', s.getpeername(),'is empty')
outputs.remove(s)
else:
print('sending "%s" to %s'% (next_msg, s.getpeername()))
s.send(next_msg)
# Handle "exceptional conditions"
forsinexceptional:
print('handling exceptional condition for', s.getpeername())
# Stop listening for input on the connection
inputs.remove(s)
ifsinoutputs:
outputs.remove(s)
s.close()
# Remove message queue
delmessage_queues[s]
客户端:
importsocket
importsys
messages = ['This is the message. ',
'It will be sent ',
'in parts.',
]
server_address = ('localhost',9999)
# Create a TCP/IP socket
socks = [socket.socket(socket.AF_INET, socket.SOCK_STREAM),
socket.socket(socket.AF_INET, socket.SOCK_STREAM),
]
# Connect the socket to the port where the server is listening
print>> sys.stderr,'connecting to %s port %s'% server_address
forsinsocks:
s.connect(server_address)
formessageinmessages:
# Send messages on both sockets
forsinsocks:
print>> sys.stderr,'%s: sending "%s"'% (s.getsockname(), message)
s.send(message)
# Read responses on both sockets
forsinsocks:
data = s.recv(1024)
print>> sys.stderr,'%s: received "%s"'% (s.getsockname(), data)
if notdata:
print>> sys.stderr,'closing socket', s.getsockname()
s.close()
原文:http://pymotw.com/2/select/
经过实验,其实windows也是支持的。
注:
select()方法接收并监控3个通信列表, 第一个是所有的输入的data,就是指外部发过来的数据,第2个是监控和接收所有要发出去的data(outgoing data),第3个监控错误信息。
当你把inputs,outputs,exceptional(这里跟inputs共用)传给select()后,它返回3个新的list,我们上面将他们分别赋值为readable,writable,exceptional, 所有在readable list中的socket连接代表有数据可接收(recv),所有在writable list中的存放着你可以对其进行发送(send)操作的socket连接,当连接通信出现error时会把error写到exceptional列表中。
Readable list 中的socket 可以有3种可能状态,第一种是如果这个socket是main "server" socket,它负责监听客户端的连接,如果这个main server socket出现在readable里,那代表这是server端已经ready来接收一个新的连接进来了,为了让这个main server能同时处理多个连接,在下面的代码里,我们把这个main server的socket设置为非阻塞模式。
第二种情况是这个socket是已经建立了的连接,它把数据发了过来,这个时候你就可以通过recv()来接收它发过来的数据,然后把接收到的数据放到queue里,这样你就可以把接收到的数据再传回给客户端了。
第三种情况就是这个客户端已经断开了,所以你再通过recv()接收到的数据就为空了,所以这个时候你就可以把这个跟客户端的连接关闭了。
对于writable list中的socket,也有几种状态,如果这个客户端连接在跟它对应的queue里有数据,就把这个数据取出来再发回给这个客户端,否则就把这个连接从output list中移除,这样下一次循环select()调用时检测到outputs list中没有这个连接,那就会认为这个连接还处于非活动状态
最后,如果在跟某个socket连接通信过程中出了错误,就把这个连接对象在inputs\outputs\message_queue中都删除,再把连接关闭掉
注解转自http://www.cnblogs.com/alex3714/p/4372426.html。
部分源码有问题我已自行修改。