Search code examples
pythonpython-3.xselectblockingpython-multithreading

Terminating loop using stream selector in Python 3


I've got some code running in a thread to wait for an incoming client connection using a socket:

import threading
import socket
import selectors

class Server(threading.Thread):
    def __init__(self):
        # instantiate socket
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

        # bind the socket
        self.socket.bind(("localhost", 50000))

    def run(self):
        # create selector to interface with OS
        sel = selectors.DefaultSelector()

        # register the connection handler for when a client connects
        sel.register(self.socket, selectors.EVENT_READ, self.handle_connection)

        while True:
            events = sel.select()
            for key, _ in events:
                # run the callback
                key.data()

    def handle_connection(self):
        # handle a request on the socket
        data = self._socket.accept()

        # do stuff with data...

    def stop(self):
        # what to do?
        pass

This code enters the while True loop and calls sel.select() which blocks until something is read from self._socket, upon which it calls the callback self.handle_connection (not relevant to my question). This works nicely, but what I'd also like to be able to do is to break the while True loop using the thread's stop method, so that my main program loop elsewhere can stop the thread and shut down the server gracefully.

I can't just check a flag like while self.running: because sel.select() blocks until something is read. I also thought about using the selector's error handling mechanism, but I don't necessarily want to shut down the server just during errors/exceptions.

It seems like I need the selector to read from a second stream which would contain a special command to stop the loop, but this seems overly complicated. Any suggestions would be appreciated!


Solution

  • Since you've said that you're ok with using a while self.flag instead of while True, you may specify a timeout parameter, as explained in the docs. Just make sure to check your data before entering the for key, _ in events: loop