Question

I couldn't find this in the docs, but how am I meant to break out of the asyncore.loop() without using signals?

Was it helpful?

Solution

That was quick to work out after looking at the source code. Thanks to the docs for linking directly to the source!

There is an ExitNow exception you can simply raise from the app, which exits the loop.

Using the EchoHandler example from the docs, I've modified it to quit immediately when receiving data.

class EchoHandler(asyncore.dispatcher_with_send):

    def handle_read(self):
        data = self.recv(8192)
        if data:
            raise asyncore.ExitNow('Server is quitting!')

Also, keep in mind that you can catch ExitNow so your app doesn't raise if you're using it internally. This is some of my source:

def run(config):
    instance = LockServer(config)
    try:
        asyncore.loop()
    except asyncore.ExitNow, e:
        print e

OTHER TIPS

The asyncore loop also quits when there are no connections left, so you could just close the connection. If you have multiple connections going on then you can use asyncore.close_all().

Try this:

One class for the server (extends asyncore.dispatcher):

class Server(asyncore.dispatcher):

    def __init__(self, port):
        asyncore.dispatcher.__init__(self)

        self.host = socket.gethostname()
        self.port = port

        self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
        self.set_reuse_addr()
        self.bind((self.host, self.port))
        self.listen(5)
        print "[Server] Listening on {h}:{p}".format(h=self.host, p=self.port)

    def handle_accept(self):
        pair = self.accept()
        if pair is not None:
            sock, addr = pair
            print "[ServerSocket] We got a connection from {a}".format(a=addr)
            SocketHandler(sock)

Another class for the thread who is going to manage the server (extends Thread)...check the run() method, there is where we call asyncore.loop():

class ServerThread(threading.Thread):
    def __init__(self, port):
        threading.Thread.__init__(self)
        self.server = Server(port)

    def run(self):
        asyncore.loop()

    def stop(self):
        self.server.close()
        self.join()

Now to start the server:

# This is the communication server, it is going to listen for incoming connections, it has its own thread:
s = ServerThread(PORT)
s.start()               # Here we start the thread for the server
print "Server is ready..."
print "Is ServerThread alive? {t}".format(t=str(s.is_alive()))
raw_input("Press any key to stop de server now...")
print "Trying to stop ServerThread..."
s.stop()
print "The server will die in 30 seconds..."

You will note that the server doesn't die immediately... but it dies gracefully

Another approach is to use the count parameter of asyncore.loop call. You can then wrap asyncore.loop in other logic:

while(i_should_continue()):
    asyncore.loop(count=1)

This won't immediately stop an open connection, or prematurely timeout. But this is probably a good thing? I'm using this when I start a listening server.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top