How to quit an asyncore dispatcher from a handler?
Asked Answered
B

4

7

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

Bikol answered 7/5, 2012 at 22:35 Comment(0)
B
8

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
Bikol answered 7/5, 2012 at 22:37 Comment(0)
M
6

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().

Maintop answered 12/5, 2013 at 12:53 Comment(1)
This method feels like such a graceful exit compared to throwing an exception. But , I guess it depends on how you would like to handle it.Ranie
F
5

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

Fretted answered 2/5, 2014 at 17:7 Comment(0)
F
4

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.

Frigidarium answered 31/1, 2014 at 15:45 Comment(1)
This is probably the the proper solution if you want to stop the loop from "outside of the loop". The other solutions above are for stopping the loop within the loop.Searle

© 2022 - 2024 — McMap. All rights reserved.