Skip to content
Advertisement

How can I get a socket’s .recv() not to block?

I’m trying to write a simple daemon that listens for orders on a Unix socket. The following works, but the connection.recv(1024) line blocks, meaning I can’t kill the server gracefully:

JavaScript

Ideally, I’d like to place all of this inside a Thread that checks a self.should_stop property every self.LOOP_TIME seconds, and if that value is set to True, then exit. However, as that .recv() line blocks, there’s no way for my program to be doing anything other than waiting at any given time.

Surely there’s a proper way to do this, but as I’m new to sockets, I have no idea what that is.

Edit

Jeremy Friesner’s answer put me on the right track. I realised that I could allow the thread to block and simply set .should_stop then pass an b"" to the socket so that it’d un-block, see that it should stop, and then exit cleanly. Here’s the end result:

JavaScript

Advertisement

Answer

Using arbitrary-length timeouts is always a bit unsatisfactory — either you set the timeout-value to a relatively long time, in which case your program becomes slow to react to the quit-request, because it is pointlessly waiting for timeout period to expire… or you set the timeout-value to a relatively short time, in which case your program is constantly waking up to see if it should quit, wasting CPU power 24/7 to check for an event which might never arrive.

A more elegant way to deal with the problem is to create a pipe, and send a byte on the pipe when you want your event-loop to exit. Your event loop can simultaneously “watch” both the pipe’s reading-end file-descriptor and your networking-socket(s) via select(), and when that file-descriptor indicates it is ready-for-read, your event loop can respond by exiting. This approach is entirely event-driven, so it requires no CPU wakeups except when there is actually something to do.

Below is an example version of your program that implements a signal-handler for SIGINT (aka pressing Control-C) to sends the please-quit-now byte on the pipe:

JavaScript
Advertisement