【问题标题】:ReactorNotRestartable errorReactorNotRestartable 错误
【发布时间】:2014-05-12 05:09:13
【问题描述】:

我有一个工具,我正在实现网络中连接的设备的 upnp 发现。

为此,我编写了一个脚本并在其中使用了数据报类。

实施: 每当在工具上按下扫描按钮时,它将运行该 upnp 脚本并在工具中创建的框中列出设备。

这工作正常。

但是当我再次按下扫描按钮时,它给了我以下错误:

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

upnp脚本的主要功能:

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

有一个服务器类正在发送 M-search 命令(upnp)以发现设备。

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)

在服务器类构造函数中,发送 m-search 后我正在弯腰反应器

reactor.callLater(10, reactor.stop)

从谷歌我发现,我们不能重启反应堆,因为这是它的限制。

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

请指导我如何修改我的代码,以便我能够扫描设备超过 1 次并且不会收到此“反应堆不可重启错误”

【问题讨论】:

    标签: python-2.7 upnp reactor twisted.internet


    【解决方案1】:

    在回答“请指导我如何修改我的代码...”时,您没有提供足够的代码,我知道如何专门指导您,我需要了解围绕您的扫描/搜索的逻辑。

    如果我要为“扭曲的反应器”提供一个通用的设计/模式/心理模型,我会说将其视为您的程序主循环。 (想想reactor 这样的问题对我来说是显而易见的......)

    I.E.大多数长时间运行的程序都有类似的形式

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

    twisted 中的相同代码更像:

    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
    

    如果您将反应堆视为“构成我的程序的main() 的无限循环”,那么您就会明白为什么没有人愿意为“重新启动”反应堆添加支持。为什么要重新启动无限循环?与其停止程序的核心,不如只手术式地停止其中已完成的任务,保持主循环不变。

    您似乎在暗示当前代码将在反应堆运行时无休止地“发送 m-search”。因此,请更改您的发送代码,使其停止重复“发送”(...我无法告诉您如何执行此操作,因为您没有提供代码,但是例如,可以通过调用 LoopingCall 来关闭它.stop 方法。

    可运行示例如下:

    #!/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()
    

    这个脚本有多余的东西,你可能不关心,所以只需关注PollingIOThingys polling try 方法中的self.l.stop()main() 中的l 相关内容即可说明这一点。

    (此代码来自 SO:Persistent connection in twisted 如果您想知道额外位是关于什么的,请检查该问题)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-02-18
      • 2017-07-12
      • 2018-08-27
      • 2018-12-13
      相关资源
      最近更新 更多