2016-07-01 6 views
0

Ich versuche, eine Funktion zu implementieren, die als Twisted-Client fungiert. Es heißt Code, über den ich keine Kontrolle habe. Ich habe versucht, so etwas wie (das aus dem pbsimpleclient.py Beispielcode genommen):verdrehter Client-Aufruf von einer Bibliotheksfunktion

# Copyright (c) Twisted Matrix Laboratories. 
# See LICENSE for details. 


from twisted.spread import pb 
from twisted.internet import reactor 
from twisted.python import util 

def remcall(**kw): 
    factory = pb.PBClientFactory() 
    reactor.connectTCP("localhost", 8789, factory) 
    d = factory.getRootObject() 
    # kw here is what's passed in via remcall 
    d.addCallback(lambda object: object.callRemote("echo", kw)) 
    d.addCallback(lambda echo: 'server echoed: '+repr(echo)) 
    d.addErrback(lambda reason: 'error: '+str(reason.value)) 
    d.addCallback(util.println) 
    d.addCallback(lambda _: reactor.stop()) 
    reactor.run() 

Und der Anrufer würde ein Anruf wie machen:

remcall(hello=1, world=2) 
remcall(hi=3, there=4) 

Aber wie Sie schon erraten kann, gibt es eine " twisted.internet.error.ReactorNotRestartable "Fehler.

Was ist der beste Weg, dies zu tun? Ich bin nicht so besorgt um eine Antwort von der Remote-Ende, aber ich sollte wissen, ob es scheitert und warum.

+0

Sie starten/stoppen nicht, der Reaktor in der Funktion. Sie starten es am Ende Ihrer Hauptfunktion und stoppen es, wenn Sie das Programm beenden wollen. Einmal. –

+0

Aber gibt es eine Möglichkeit, es laufen zu lassen (vielleicht in einem Thread) und lassen Sie den Haupt-Thread zum Anrufer zurückkehren? Oder ist das etwas, das mit Twisted nicht gemacht werden kann? – mlv

Antwort

0

Die Antwort ist zu häkeln.

# Copyright (c) Twisted Matrix Laboratories. 
# See LICENSE for details. 

## Add these two lines 
from crochet import setup, wait_for 
setup() 

from twisted.spread import pb 
from twisted.internet import reactor 
from twisted.python import util 

## Add a wait_for decorator 
@wait_for(timeout=5.0) 
def remcall(**kw): 
    factory = pb.PBClientFactory() 
    reactor.connectTCP("localhost", 8789, factory) 
    d = factory.getRootObject() 
    # kw here is what's passed in via remcall 
    d.addCallback(lambda object: object.callRemote("echo", kw)) 
    d.addCallback(lambda echo: 'server echoed: '+repr(echo)) 
    d.addErrback(lambda reason: 'error: '+str(reason.value)) 
    d.addCallback(util.println) 
## Get rid of the reactor calls, and return d 
# d.addCallback(lambda _: reactor.stop()) 
# reactor.run() 
    return d 

Dann wird der Anrufer ruft nur

remcall(hello=1, world=2) 
remcall(hi=3, there=4) 

und Häkeln des @wait_for Griffe remcall im Inneren des Reaktors Thread ausgeführt wird.

1

Entfernen Sie reactor.run() von der remcall Funktion und fügen Sie sie am Ende an. Auch entfernen d.addCallback(lambda _: reactor.stop())

def remcall(**kw): 
    factory = pb.PBClientFactory() 
    reactor.connectTCP("localhost", 8789, factory) 
    d = factory.getRootObject() 
    # kw here is what's passed in via remcall 
    d.addCallback(lambda object: object.callRemote("echo", kw)) 
    d.addCallback(lambda echo: 'server echoed: '+repr(echo)) 
    d.addErrback(lambda reason: 'error: '+str(reason.value)) 
    d.addCallback(util.println) 


remcall(hello=1, world=2) 
remcall(hi=3, there=3) 
reactor.run() # this should be the last thing to run 

Der Reaktor kann nur einmal ausgeführt werden. reactor.stop() Funktion wird ausgeführt und es sollte nicht, es sei denn, Ihre Anwendung muss nicht mehr vollständig ausgeführt werden. Aus diesem Grund erhalten Sie die Ausnahme ReactorNotRestartable.

+0

Sie haben die Frage missverstanden. Anderer Code, über den ich keine Kontrolle habe, ruft remcall viele Male auf, und jedes Mal muss eine Verbindung zur entfernten Seite hergestellt werden. – mlv

+0

Die Antwort zeigt mehrere Anrufe zu remcall, so wie es scheint, dass Sie möchten. Lassen Sie sich nicht dadurch täuschen, dass beide Aufrufe vor dem Aufruf von reactor.run() in diesem Beispiel stattfinden. Sie würden genauso gut funktionieren, wenn sie nach reactor.run() hergestellt würden. Was Sie jedoch nicht tun können, ist "reactor.run(); remcall (...)", weil reactor.run() nicht zurückkehrt, bis der Reaktor stoppt. Stattdessen brauchen Sie einen anderen Thread, um etwas wie "reactor.callFromThread (lambda: remcall (...))" zu machen oder um den remcall (...) in einen Twisted Event-Handler zu schreiben. –

+1

Also @mlv sagst du, dass der Code, über den du keine Kontrolle hast, "remcall" importieren und ausführen wird? Wird der andere Code mit Twisted geschrieben? Wenn das nicht der Fall ist, müssen Sie den Reaktor und die Funktion in einem Thread ausführen, und der einfachste Weg dazu ist "häkeln" https://github.com/itamarst/crochet/. Sorry für das Missverständnis, hoffentlich habe ich es jetzt -__- –

Verwandte Themen