我有一个工具,我正在实现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不能重启错误"
答案 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 try
和l
相关内容main()
说明了这一点。
(此代码来自SO:Persistent connection in twisted如果您想知道额外位是什么,请检查该问题)