ReactorNotRestartable错误

时间:2014-05-12 05:09:13

标签: python-2.7 upnp reactor twisted.internet

我有一个工具,我正在实现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次并且没有得到这个" reactor不能重启错误"

1 个答案:

答案 0 :(得分:1)

回应“请指导我如何修改我的代码......”,你没有提供足够的代码,我知道如何专门指导你,我需要了解(扭曲的部分)扫描/搜索周围的逻辑。

如果我要为“扭曲反应堆”提供通用设计/模式/心理模型,我会说将其视为您的程序主循环。 (考虑reactor这种方式是什么使问题显而易见......“

即。大多数长时间运行的程序都有类似

的形式
def main():
    while(True):
       check_and_update_some_stuff()
       sleep 10

扭曲中的相同代码更像是:

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方法。

Runnable示例如下:

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

此脚本中有一些您可能不关心的内容,因此请关注self.l.stop() PollingIOThingy方法中的polling tryl相关内容main()说明了这一点。

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