{
  "$type": "site.standard.document",
  "canonicalUrl": "https://rednafi.com/python/pause-and-resume-a-socket-server/",
  "description": "Build a pausable socket server with Python's socketserver module using threading for intermittent request handling and background tasks.",
  "path": "/python/pause-and-resume-a-socket-server/",
  "publishedAt": "2023-02-05T00:00:00.000Z",
  "site": "at://did:plc:fgtm2c26vfcj74rfmeggbyqj/site.standard.publication/3mnl6f7ob462z",
  "tags": [
    "Python",
    "Networking",
    "Concurrency"
  ],
  "textContent": "I needed to write a socket server in Python that would allow me to intermittently pause the\nserver loop for a while, run something else, then get back to the previous request-handling\nphase; repeating this iteration until the heat death of the universe. Initially, I opted for\nthe low-level socket module to write something quick and dirty. However, the\nimplementation got hairy pretty quickly. While the socket module gives you plenty of\ncontrol over how you can tune the server's behavior, writing a server with robust signal and\nerror handling can be quite a bit of boilerplate work.\n\nThankfully, I found out that Python is already shipped with a higher level library named\n[socketserver] that uses the socket module underneath but gives you more tractable hooks\nto latch onto and build fairly robust servers where the low-level details are handled for\nyou. Not only that, socketserver makes it easy to write a sever that can concurrently\nhandle multiple clients either by spinning child threads or forking child processes.\n\nWhile all this sounds good and dandy, my primary objective was to be able to write a server\nthat can pause serving the clients every now and then, do some work and then come back to\nthe previous work. Here's how I did it with a multi-threaded socket server:\n\nThis is a simple echo server that receives client connections and reflects back the data\nsent by the clients. The server can handle multiple client connections simultaneously using\nthe ThreadingTCPServer class. This class is derived from the\nsocketserver.ThreadingTCPServer class and is responsible for implementing the server's\nmain loop, which listens for incoming client connections and creates a separate thread for\neach one to handle the incoming request.\n\nThe RequestHandler class is used to handle each incoming request. This class is derived\nfrom the socketserver.BaseRequestHandler class and is responsible for handling the\nconnection between a client and the server. It implements the setup, handle, and\nfinish methods to perform any necessary initialization work, handle the incoming data, and\nclean up after the request has been processed. In the setup and finish methods, we're\nonly printing some message to indicate that these methods are called before and after the\nhandle method respectively. In the handle method, we're collecting the data sent by the\nclients and echoing them back. Here, inside the while loop, conn.recv is a blocking\nmethod and will keep reading from the clients indefinitely. We need the server to break out\nfrom this, do something else, and then get back to it gracefully.\n\nIn the __main__ section of the code snippet, a ThreadingTCPServer object is created and\nthe server is started using the serve_forever method. This method will continuously run\nthe server loop, listen for incoming connections and create a separate thread for each one\nto handle the request.\n\nThe ThreadingTCPServer class implements server_activate and get_request methods. These\ntwo methods are already implemented in the base and we're just calling the methods from\nthere with some additonal logging. Here, server_activate prints out the server's IP\naddress and port. Similarly, the get_request method calls the eponymous method from the\nsuperclass and logs the IP and the port of the incoming clients.\n\nThe server also implements a service_actions method that is called by the server loop.\nThis is where we're periodically pausing the server and performing some blocking actions. In\nthis case, the service_actions method checks the current time and compares it to the start\ntime of the server. If the difference is greater than the specified timeout, the server is\npaused and a message is printed to the console indicating that something else is running.\nThen after one iteration, the start time is updated so that the server gets paused again\nafter the timeout period.\n\nTo test the server out, here's a simple client that sends some data to the server:\n\nThis client connects to the server via port 9999 and sends the b'hello world' byte\nstring. The server will capture and echo it back to the client which the client will print\nas Received .... You can run the server in one console with python server.py and the\nclient in another one with the python client.py command.\n\n![Terminal showing socket server pausing and resuming while handling client connections][image_1]\n\nYou'll see that the server will pause every 5 seconds, do something else in a blocking\nmanner and then come back to handle the client requests. If you attach a second client from\nanother console, you'll see that the server can also handle that while retaining the\nexpected behavior. The server will pause even if there's no client sending requests to the\nserver. You can test that behavior by detaching all the clients from the server.\n\nNow, we could also make the work in the serving_actions non-blocking by spinning a new\nthread or process and doing the work there. However, for the task that I was tackling,\nsimply running the function in a blocking manner was enough.\n\n\n\n\n[socketserver]:\n    https://docs.python.org/3/library/socketserver.html\n\n[image_1]:\n    https://blob.rednafi.com/static/images/pause_and_resume_a_socket_server/img_1.png",
  "title": "Pausing and resuming a socket server in Python"
}