在linux上编写socket服务端程序一般可以用select、poll、epoll三种方式,本文主要介绍使用poll和epoll编写socket服务端模块。
使用poll方式的服务器端程序代码:
import socket import select import Queue server_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 event READ_ONLY = ( select.POLLIN | select.POLLPRI | select.POLLHUP | select.POLLERR) READ_WRITE = (READ_ONLY|select.POLLOUT) # Set up the poller poller = 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 socket import select import Queue server_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 event READ_ONLY = ( select.EPOLLIN | select.EPOLLPRI | select.EPOLLHUP | select.EPOLLERR) READ_WRITE = (READ_ONLY|select.EPOLLOUT) # Set up the poller epoller = 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]
客户端程序代码与上一篇博文中的相同。