I l@ve RuBoard |
10.3 Writing a TCP ServerCredit: Luther Blissett 10.3.1 ProblemYou want to write a server that waits for clients to connect over the network to a particular port. 10.3.2 SolutionAssuming you're using the Internet to communicate: import socket # Create a socket sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # Ensure that you can restart your server quickly when it terminates sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # Set the client socket's TCP "well-known port" number well_known_port = 8881 sock.bind(('', well_known_port)) # Set the number of clients waiting for connection that can be queued sock.listen(5) # loop waiting for connections (terminate with Ctrl-C) try: while 1: newSocket, address = sock.accept( ) print "Connected from", address # loop serving the new client while 1: receivedData = newSocket.recv(1024) if not receivedData: break # Echo back the same data you just received newSocket.send(receivedData) newSocket.close( ) print "Disconnected from", address finally: sock.close( ) 10.3.3 DiscussionSetting up a server takes a bit more work than setting up a client. We need to bind to a well-known port that clients will use to connect to us. Optionally, as we do in this recipe, we can set SO_REUSEADDR so we can restart the server when it terminates without waiting for a few minutes, which is quite nice during development and testing. We can also optionally call listen to control the number of clients waiting for connections that can be queued. After this preparation, we just need to loop, waiting for the accept method to return; it returns a new socket object already connected to the client and the client's address. We use the new socket to hold a session with a client, then go back to our waiting loop. In this recipe, we just echo back the same data we receive from the client. The SocketServer module lets us perform the same task in an object-oriented way. Using it, the recipe becomes: import SocketServer class MyHandler(SocketServer.BaseRequestHandler): def handle(self): while 1: dataReceived = self.request.recv(1024) if not dataReceived: break self.request.send(dataReceived) myServer = SocketServer.TCPServer(('',8881), MyHandler) myServer.serve_forever( ) One handler object is instantiated to serve each connection, and the new socket for that connection is available to its handle method (which the server calls) as self.request. Using the SocketServer module instead of the lower-level socket module is particularly advisable when we want more functionality. For example, to spawn a new and separate thread for each request we serve, we would need to change only one line of code in this higher-level solution: myServer = SocketServer.ThreadingTCPServer(('',8881), MyHandler) while the socket-level recipe would need substantially more recoding to be transformed into a similarly multithreaded server. 10.3.4 See AlsoRecipe 10.2; documentation for the standard library module socket in the Library Reference; Perl Cookbook Recipe 17.2. |
I l@ve RuBoard |