Ошибка ReactorNotRestartable

У меня есть инструмент, в котором я реализую обнаружение 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)

Из google я обнаружил, что мы не можем перезапустить реактор, потому что это его ограничение.

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

Пожалуйста, помогите мне, как я могу изменить свой код, чтобы я мог сканировать устройства более 1 раза и не получать эту «ошибку, не перезапускаемую реактором»


person Patrick    schedule 12.05.2014    source источник


Ответы (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 .

Запускаемый пример следующим образом:

#!/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() в PollingIOThingys polling try и на связанных с l вещах в main(), чтобы проиллюстрировать суть.

(этот код исходит из SO: Постоянное соединение в скрученном проверьте этот вопрос, если вы хотите знать, что такое дополнительные биты)

person Mike Lutz    schedule 12.05.2014