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 

デバイスを複数回スキャンでき、この「reactor not restartable error」が発生しないように、コードを変更する方法を教えてください。

4

1 に答える 1

1

「私のコードを変更するにはどうすればよいか教えてください...」への対応として、あなたは具体的にあなたを導く方法を知るのに十分なコードを提供していません.あなたの周りのロジックの(ねじれた部分)を理解する必要があります.スキャン/検索。

ただし、「ねじれたリアクター」の一般的な設計/パターン/メンタルモデルを提供するとしたら、それをプログラムのメインループと考えてくださいreactor(とにかく、そのように考えることで、問題が明らかになります...)

IE のほとんどの実行時間の長いプログラムは、次のような形式をしています。

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を呼び出すことで 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関連するものに注目してください。main()

(このコードは SO: Persistent connection in twistedから来ています。余分なビットが何であるかを知りたい場合は、その質問をチェックしてください)

于 2014-05-12T19:08:32.313 に答える