|I l@ve RuBoard|
10.3 Writing a TCP Server
Credit: Luther Blissett
Assuming 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( )
Setting 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.
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 Also
Recipe 10.2; documentation for the standard library module socket in the Library Reference; Perl Cookbook Recipe 17.2.
|I l@ve RuBoard|