ReactorNotRestartable error
Question: I have a tool, where i am implementing upnp discovery of devices connected in
network.

For that i have written a script and used datagram class in it.

Implementation: whenever scan button is pressed on tool, it will run that upnp
script and will list the devices in the box created in tool.

This was working fine.

But when i again press the scan button, it gives me following error:

    
    
    Traceback (most recent call last):
      File "tool\ui\main.py", line 508, in updateDevices
        upnp_script.main("server", localHostAddress)
      File "tool\ui\upnp_script.py", line 90, in main
        reactor.run()
      File "C:\Python27\lib\site-packages\twisted\internet\base.py", line 1191, in run
        self.startRunning(installSignalHandlers=installSignalHandlers)
      File "C:\Python27\lib\site-packages\twisted\internet\base.py", line 1171, in startRunning
        ReactorBase.startRunning(self)
      File "C:\Python27\lib\site-packages\twisted\internet\base.py", line 683, in startRunning
        raise error.ReactorNotRestartable()
    twisted.internet.error.ReactorNotRestartable
    

Main function of upnp script:

    
    
    def main(mode, iface):
        klass = Server if mode == 'server' else Client
        obj = klass
        obj(iface)
        reactor.run()
    

There is server class which is sending M-search command(upnp) for discovering
devices.

    
    
    MS = 'M-SEARCH * HTTP/1.1\r\nHOST: %s:%d\r\nMAN: "ssdp:discover"\r\nMX: 2\r\nST: ssdp:all\r\n\r\n' % (SSDP_ADDR, SSDP_PORT)
    

In server class constructor, after sending m-search i am stooping reactor

    
    
    reactor.callLater(10, reactor.stop)
    

From google i found that, we cannot restart a reactor beacause it is its
limitation.

    
    
    http://twistedmatrix.com/trac/wiki/FrequentlyAskedQuestions#WhycanttheTwistedsreactorberestarted 
    

Please guide me how can i modify my code so that i am able to scan devices
more than 1 time and don't get this "reactor not restartable error"


Answer: In response to "Please guide me how can i modify my code...", you haven't
provided enough code that I would know how to specifically guide you, I would
need to understand the (twisted part) of the logic around your scan/search.

If I were to offer a generic design/pattern/mental-model for the "twisted
reactor" though, I would say **think of it as your programs main loop**.
(thinking about the `reactor` that way is what makes the problem obvious to me
anyway...)

I.E. most long running programs have a form something like

    
    
    def main():
        while(True):
           check_and_update_some_stuff()
           sleep 10
    

That same code in twisted is more like:

    
    
    def main():
        # the LoopingCall adds the given function to the reactor loop
        l = task.LoopingCall(check_and_update_some_stuff)
        l.start(10.0)
        reactor.run() # <--- this is the endless while loop
    

If you think of the reactor as "the endless loop that makes up the `main()` of
my program" then you'll understand why no-one is bothering to add support for
"restarting" the reactor. Why would you want to restart an endless loop?
Instead of stopping the core of your program, you should instead only
surgically stop the task inside that is complete, leaving the main loop
untouched.

You seem to be implying that the current code will keep "sending m-search"s
endlessly when the reactor is running. So change your sending code so it stops
repeating the "send" (... I can't tell you how to do this because you didn't
provide code, but for instance, a `LoopingCall` can be turned off by calling
its `.stop` method.

Runnable example as follows:

    
    
    #!/usr/bin/python
    
    from twisted.internet import task
    from twisted.internet import reactor
    from twisted.internet.protocol import Protocol, ServerFactory
    
    class PollingIOThingy(object):
        def __init__(self):
            self.sendingcallback = None # Note I'm pushing sendToAll into here in main()
            self.l = None # Also being pushed in from main()
            self.iotries = 0
    
        def pollingtry(self):
            self.iotries += 1
            if self.iotries > 5:
                print "stoping this task"
                self.l.stop()
                return()
            print "Polling runs: " + str(self.iotries)
            if self.sendingcallback:
                self.sendingcallback("Polling runs: " + str(self.iotries) + "\n")
    
    class MyClientConnections(Protocol):
        def connectionMade(self):
            print "Got new client!"
            self.factory.clients.append(self)
    
        def connectionLost(self, reason):
            print "Lost a client!"
            self.factory.clients.remove(self)
    
    class MyServerFactory(ServerFactory):
        protocol = MyClientConnections
    
        def __init__(self):
            self.clients = []
    
        def sendToAll(self, message):
          for c in self.clients:
            c.transport.write(message)
    
    
    # Normally I would define a class of ServerFactory here but I'm going to
    # hack it into main() as they do in the twisted chat, to make things shorter
    
    def main():
        client_connection_factory = MyServerFactory()
    
        polling_stuff = PollingIOThingy()
    
        # the following line is what this example is all about:
        polling_stuff.sendingcallback = client_connection_factory.sendToAll
        # push the client connections send def into my polling class
    
        # if you want to run something ever second (instead of 1 second after
        # the end of your last code run, which could vary) do:
        l = task.LoopingCall(polling_stuff.pollingtry)
        polling_stuff.l = l
        l.start(1.0)
        # from: https://twistedmatrix.com/documents/12.3.0/core/howto/time.html
    
        reactor.listenTCP(5000, client_connection_factory)
        reactor.run()
    
    if __name__ == '__main__':
      main()
    

This script has extra cruft in it that you might not care about, so just focus
on the `self.l.stop()` in `PollingIOThingy`s `polling try` method and the `l`
related stuff in `main()` to illustrates the point.

(this code comes from SO: [Persistent connection in
twisted](http://stackoverflow.com/q/23265609/3334178) check that question if
you want to know what the extra bits are about)

