在linux上编写socket服务端程序一般可以用select、poll、epoll三种方式,本文主要介绍使用poll和epoll编写socket服务端模块。
使用poll方式的服务器端程序代码:
import socketimport selectimport Queueserver_address=('10.0.2.15',21345)server=socket.socket(socket.AF_INET,socket.SOCK_STREAM)server.setblocking(False)server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)server.bind(server_address)server.listen(5)message_queues={}#poll时间单位是毫秒timeout = 1000# Create a limit for the eventREAD_ONLY = ( select.POLLIN | select.POLLPRI | select.POLLHUP | select.POLLERR)READ_WRITE = (READ_ONLY|select.POLLOUT)# Set up the pollerpoller = select.poll()poller.register(server,READ_ONLY)#Map file descriptors to socket objects#server.fileno()是获得server这个socket的文件描述符,是int类型fd_to_socket = {server.fileno():server,}while True: events = poller.poll(timeout) #fd是描述符,flag是event状态,都是int类型 for fd ,flag in events: # Retrieve the actual socket from its file descriptor #s为当前的socket对象 s = fd_to_socket[fd] if flag & (select.POLLIN | select.POLLPRI) : if s is server : # A readable socket is ready to accept a connection connection , client_address = s.accept() print " Connection " , client_address connection.setblocking(False) fd_to_socket[connection.fileno()] = connection poller.register(connection,READ_ONLY) #Give the connection a queue to send data message_queues[connection] = Queue.Queue() else : data = s.recv(1024) if data: # A readable client socket has data print " received %s from %s " % (data, s.getpeername()) message_queues[s].put(data) poller.modify(s,READ_WRITE) else : # Close the connection print " closing" , s.getpeername() # Stop listening for input on the connection poller.unregister(s) s.close() del message_queues[s] elif flag & select.POLLHUP : #A client that "hang up" , to be closed. print " Closing ", s.getpeername() ,"(HUP)" poller.unregister(s) s.close() 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 s.getpeername() , " queue empty" poller.modify(s,READ_ONLY) else : print " sending %s to %s" % (next_msg , s.getpeername()) s.send(next_msg) elif flag & select.POLLERR: #Any events with POLLERR cause the server to close the socket print " exception on" , s.getpeername() poller.unregister(s) s.close() del message_queues[s]
使用epoll方式的服务器端程序代码跟poll方式类似,具体代码如下:
import socketimport selectimport Queueserver_address=('10.0.2.15',21345)server=socket.socket(socket.AF_INET,socket.SOCK_STREAM)server.setblocking(False)server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)server.bind(server_address)server.listen(5)message_queues={}#poll时间单位是毫秒timeout = 1000# Create a limit for the eventREAD_ONLY = ( select.EPOLLIN | select.EPOLLPRI | select.EPOLLHUP | select.EPOLLERR)READ_WRITE = (READ_ONLY|select.EPOLLOUT)# Set up the pollerepoller = select.epoll()epoller.register(server,READ_ONLY)#Map file descriptors to socket objects#server.fileno()是获得server这个socket的文件描述符,是int类型fd_to_socket = {server.fileno():server,}while True: print "Waiting for the next event" events = epoller.poll(timeout) print events #fd是描述符,flag是event状态 for fd ,flag in events: # Retrieve the actual socket from its file descriptor s = fd_to_socket[fd] if flag & (select.EPOLLIN | select.EPOLLPRI) : if s is server : # A readable socket is ready to accept a connection connection , client_address = s.accept() print " Connection " , client_address connection.setblocking(False) fd_to_socket[connection.fileno()] = connection epoller.register(connection,READ_ONLY) #Give the connection a queue to send data message_queues[connection] = Queue.Queue() else : data = s.recv(1024) if data: # A readable client socket has data print " received %s from %s " % (data, s.getpeername()) message_queues[s].put(data) epoller.modify(s,READ_WRITE) else : # Close the connection print " closing" , s.getpeername() # Stop listening for input on the connection epoller.unregister(s) s.close() del message_queues[s] elif flag & select.EPOLLHUP : #A client that "hang up" , to be closed. print " Closing ", s.getpeername() ,"(HUP)" epoller.unregister(s) s.close() 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 s.getpeername() , " queue empty" epoller.modify(s,READ_ONLY) else : print " sending %s to %s" % (next_msg , s.getpeername()) s.send(next_msg) elif flag & select.EPOLLERR: #Any events with POLLERR cause the server to close the socket print " exception on" , s.getpeername() epoller.unregister(s) s.close() del message_queues[s]
客户端程序代码与上一篇博文中的相同。