2

我有一个工具,我在其中实现网络中连接的设备的 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 次并且不会收到此“反应堆不可重启错误”

4

1 回答 1

1

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

但是,如果我要为“扭曲的反应器”提供通用设计/模式/心理模型,我会说将其视为您的程序 main loop。(考虑reactor这种方式是什么让问题对我来说很明显......)

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

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来关闭a。.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()

该脚本中包含您可能不关心的额外内容,因此只需关注self.l.stop()in PollingIOThingyspolling try方法和l相关内容 inmain()即可说明这一点。

(此代码来自 SO:Persistent connection in twisted check that question if you want to know what the extra bits are about)

于 2014-05-12T19:08:32.313 回答