Discussion:
[Twisted-Python] Restarting a reactor listener
i***@facilita.co.uk
2006-08-01 17:27:54 UTC
Permalink
I have created an internet server that is started in a thread from a Python QT GUI.

I can call reactor.stop() and sucessfully get notified of shutdown and the run thread terminates, the TCP/IP listen port is closed.

When I restart it by calling reactor.listenTCP() and reactor.run(installSignalHandlers=0) a second time I find that things don't work correctly. e.g. TCP calls are accepted and my protocol.dataReceived() is called but then calling reactor.callInThread(self.blockingMethod, data) does nothing. Also calling stop() a second time does not stop the running reactor thread or terminate the TCP listener.

I have tried numerous options, and have been careful to avoid any conflicts with the GUI threads. It appears that the reactor is not being restarted correctly after stop() and a second run().

What I need is to stop and re-start the listenTCP. Is there a way to do this?

Thanks,
Ian
Jean-Paul Calderone
2006-08-01 17:44:23 UTC
Permalink
Post by i***@facilita.co.uk
I have created an internet server that is started in a thread from a Python QT GUI.
I can call reactor.stop() and sucessfully get notified of shutdown and the run thread terminates, the TCP/IP listen port is closed.
When I restart it by calling reactor.listenTCP() and reactor.run(installSignalHandlers=0) a second time I find that things don't work correctly. e.g. TCP calls are accepted and my protocol.dataReceived() is called but then calling reactor.callInThread(self.blockingMethod, data) does nothing. Also calling stop() a second time does not stop the running reactor thread or terminate the TCP listener.
I have tried numerous options, and have been careful to avoid any conflicts with the GUI threads. It appears that the reactor is not being restarted correctly after stop() and a second run().
What I need is to stop and re-start the listenTCP. Is there a way to do this?
You need to implement this feature :) It is not expected to work any
currently provided reactor.

More likely, though, you just shouldn't call reactor.stop() until you're
ready to exit completely.

Jean-Paul
g***@divmod.com
2006-08-01 19:03:11 UTC
Permalink
Post by i***@facilita.co.uk
I have created an internet server that is started in a thread from a Python
QT GUI.
Although Twisted's QT reactor is not terribly well supported since nobody on the Twisted team likes QT, but starting a reactor in a non-main thread and restarting it is not "not well supported", it is very explicitly broken :).

You should look at using the QT reactor, and run your Twisted code in the same thread as your GUI -- and possibly submitting some patches so we can finally get the last of the tests passing: see http://twistedmatrix.com/buildbot/

If you have the option of using a different UI toolkit, consider using GTK2; GTK seems to behave best out of all the toolkits when dealing with asynchronous I/O, and it is definitely a favorite of a sizeable portion of the Twisted team.
Post by i***@facilita.co.uk
When I restart it (...)
As exarkun says, the reactor is not restartable.

There's a reason why nobody's bothered with this yet. While a truly restartable reactor might be of real use in a few obscure situations (mostly in test code), applications which _appear_ to require it are often just mis-designed and should be fixed to run the reactor in the "normal" way.

For a previous discussion of this issue, see this ticket, which seems to be destined for rejection: http://twistedmatrix.com/trac/ticket/893
Travis Vachon
2006-08-02 23:12:49 UTC
Permalink
Hi Ian

I ran into this just recently, but am not entirely certain I found the best
solution. I needed to be able to switch the port the reactor was listening
on without restarting the reactor. Here's how I did it:

def startListener(self, port, interface="127.0.0.1"):

self.iListeningPort = reactor.listenTCP(
port,
self.factory,
interface=interface
)
def restartListener(self, port, interface="127.0.0.1"):

self.iListeningPort.stopListening()
self.startListener(port, interface)


I'm not sure if doing this will have any unintended side-effects, but so far
it seems to have done the trick. If someone else on the list could confirm
this does what I think it does (and what Ian is looking for) that would be
great.

Best,

Travis
Post by i***@facilita.co.uk
I have created an internet server that is started in a thread from a Python QT GUI.
I can call reactor.stop() and sucessfully get notified of shutdown and the
run thread terminates, the TCP/IP listen port is closed.
When I restart it by calling reactor.listenTCP() and reactor.run(installSignalHandlers=0)
a second time I find that things don't work correctly. e.g. TCP calls are
accepted and my protocol.dataReceived() is called but then calling
reactor.callInThread(self.blockingMethod, data) does nothing. Also calling
stop() a second time does not stop the running reactor thread or terminate
the TCP listener.
I have tried numerous options, and have been careful to avoid any
conflicts with the GUI threads. It appears that the reactor is not being
restarted correctly after stop() and a second run().
What I need is to stop and re-start the listenTCP. Is there a way to do this?
Thanks,
Ian
_______________________________________________
Twisted-Python mailing list
http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python
Jean-Paul Calderone
2006-08-03 00:23:14 UTC
Permalink
Post by Travis Vachon
Hi Ian
I ran into this just recently, but am not entirely certain I found the best
solution. I needed to be able to switch the port the reactor was listening
self.iListeningPort = reactor.listenTCP(
port,
self.factory,
interface=interface
)
self.iListeningPort.stopListening()
self.startListener(port, interface)
I'm not sure if doing this will have any unintended side-effects, but so far
it seems to have done the trick. If someone else on the list could confirm
this does what I think it does (and what Ian is looking for) that would be
great.
Best,
Travis
This is pretty much exactly correct. The only thing which *might* be an
issue is that stopListening is not guaranteed to succeed immediately. *If*
you are relying on the old port number to be available immediately after
restartListener returns, you might be surprised. You can address this by
returning the Deferred which is returned by stopListening from restartListener
so that the caller will receive notification when the old port number becomes
free.

In practice, and for the typical use cases, this probably won't often be a
problem.

Jean-Paul

Loading...