http://blog.csdn.net/hongqun/article/details/19161841
#!/usr/bin/env python
# encoding: utf-8
import select
import socket
import sys
import Queue
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setblocking(0)
server_address = ('localhost', 10000)
print >>sys.stderr, 'starting up on %s port %s' % server_address
server.bind(server_address)
server.listen(5)
message_queues = {}
TIMEOUT = 1000
"""
poll的底层实现比select高效,但是poll在windows下不被支持
"""
# poll监听5种事件
# POLLIN:输入准备好
# POLLPRI:带外数据可读
# POLLOUT:准备好接受数据
# POLLERR:有错误发生
# POLLHUP:通道关闭
# POLLVAL:通道未打开
#只读事件组合
READ_ONLY = ( select.POLLIN |
select.POLLPRI |
select.POLLHUP |
select.POLLERR )
#读写事件组合
READ_WRITE = READ_ONLY | select.POLLOUT
#得到poll对象
poller = select.poll()
#在poll对象中注册server套接字,并让poller监听该套接字的READ_ONLY事件
poller.register(server, READ_ONLY)
#由于poller.poll返回的是元素为(fd,flag)的列表,所以我们必须保存fd与相应socket对象的映射
fd_to_socket = { server.fileno(): server,
}
while True:
#监听已注册的socket事件,返回元素为(描述符,事件标志)的列表
print >>sys.stderr, 'waiting for the next event'
events = poller.poll(TIMEOUT)
for fd, flag in events:
s = fd_to_socket[fd]
#处理输入事件
if flag & (select.POLLIN | select.POLLPRI):
#当有新连接到来
if s is server:
connection, client_address = s.accept()
print >>sys.stderr, ' connection', client_address
connection.setblocking(0)
fd_to_socket[ connection.fileno() ] = connection
#将与客户端通讯的socket对象注册到poll对象中,并让poll监听该对象的只读属性
poller.register(connection, READ_ONLY)
message_queues[connection] = Queue.Queue()
#客户端有数据到来
else:
data = s.recv(1024)
if data:
print >>sys.stderr, ' received "%s" from %s' % \
(data, s.getpeername())
message_queues[s].put(data)
# 让poll对象监听该套接字对象的读写属性
poller.modify(s, READ_WRITE)
#客户端断开
else:
print >>sys.stderr, ' closing', client_address
poller.unregister(s)
s.close()
del message_queues[s]
#套接字可写
elif flag & select.POLLOUT:
# Socket is ready to send data, if there is any to send.
try:
next_msg = message_queues[s].get_nowait()
except Queue.Empty:
# No messages waiting so stop checking
print >>sys.stderr, s.getpeername(), 'queue empty'
#如果没数据可写,则不监听写事件
poller.modify(s, READ_ONLY)
else:
print >>sys.stderr, ' sending "%s" to %s' % \
(next_msg, s.getpeername())
s.send(next_msg)
#通道关闭
elif flag & select.POLLHUP:
# Client hung up
print >>sys.stderr, ' closing', client_address, '(HUP)'
poller.unregister(s)
s.close()
del message_queues[s]
#发生错误
elif flag & select.POLLERR:
print >>sys.stderr, ' exception on', s.getpeername()
poller.unregister(s)
s.close()
del message_queues[s]