来自库函数的扭曲客户端调用

twisted client call from a library function

我正在尝试实现一个充当 Twisted 客户端的功能。它是从我无法控制的代码中调用的。我尝试了类似的东西(取自 pbsimpleclient.py 示例代码):

# 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()

来电者会拨打这样的电话:

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

但是您可能已经猜到了,它给出了 "twisted.internet.error.ReactorNotRestartable" 错误。

最好的方法是什么?我不太担心从远程端得到响应,但我应该知道它是否失败以及原因。

remcall 函数中删除 reactor.run() 并将其附加在末尾。同时删除 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

反应堆只能运行一次。 reactor.stop() 函数正在执行,除非您的应用程序需要完全停止 运行ning,否则它不应该执行。这就是您得到 ReactorNotRestartable 异常的原因。

答案是用钩针。

# 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

然后来电者直接调用

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

和 crochet 的 @wait_for 处理反应器线程内的 运行 remcall。