2

为什么我在尝试实现调用 AMP 命令的 LoopingCall 函数时会出错?

from twisted.protocols.amp import AMP
from twisted.python.log import startLogging, err
from twisted.internet.task import LoopingCall
from twisted.internet import reactor
from sys import stdout

import commands

startLogging(stdout)


class MyAMP:

    def __init__(self, host, port):
        destination = TCP4ClientEndpoint(reactor, host, port)
        self.protocol = AMP()
        self.d = connectProtocol(destination, self.protocol)

    def say(self):
        return self.protocol.callRemote(commands.Say,
                                   phrase='Hello world')


def loop(myamp):
    myamp.say()


def main(host, port):
    myamp = MyAMP(host, port)
    lc = LoopingCall(loop, myamp=myamp)
    lc.start(4.0)
    reactor.run()

main('127.0.0.1', 12345)

myamp.say()在循环内调用时出错:

2013-08-16 12:28:58-0400 [-] Starting factory <twisted.internet.endpoints.OneShotFactory instance at 0x92273ec>
2013-08-16 12:28:58-0400 [-] Unhandled error in Deferred:
2013-08-16 12:28:58-0400 [-] Unhandled Error
    Traceback (most recent call last):
      File "lib/client.py", line 35, in <module>
        main('127.0.0.1', 12345)
      File "lib/client.py", line 32, in main
        lc.start(4.0)
      File "/usr/local/lib/python2.7/site-packages/twisted/internet/task.py", line 173, in start
        self()
      File "/usr/local/lib/python2.7/site-packages/twisted/internet/task.py", line 218, in __call__
        d = defer.maybeDeferred(self.f, *self.a, **self.kw)
    --- <exception caught here> ---
      File "/usr/local/lib/python2.7/site-packages/twisted/internet/defer.py", line 137, in maybeDeferred
        result = f(*args, **kw)
      File "lib/client.py", line 26, in loop
        myamp.say()
      File "lib/client.py", line 22, in say
        phrase='Hello world')
      File "/usr/local/lib/python2.7/site-packages/twisted/protocols/amp.py", line 821, in callRemote
        return co._doCommand(self)
      File "/usr/local/lib/python2.7/site-packages/twisted/protocols/amp.py", line 1778, in _doCommand
        self.requiresAnswer)
      File "/usr/local/lib/python2.7/site-packages/twisted/protocols/amp.py", line 752, in _sendBoxCommand
        box._sendTo(self.boxSender)
      File "/usr/local/lib/python2.7/site-packages/twisted/protocols/amp.py", line 577, in _sendTo
        proto.sendBox(self)
    exceptions.AttributeError: 'NoneType' object has no attribute 'sendBox'

2013-08-16 12:28:58-0400 [Uninitialized] AMP connection established (HOST:IPv4Address(TCP, '127.0.0.1', 50457) PEER:IPv4Address(TCP, '127.0.0.1', 12345))
4

2 回答 2

2

您正在尝试callRemote在建立连接之前。默认情况下, ALoopingCall将在您启动它时立即运行它的功能。与其做lc.start(4.0),不如做lc.start(4.0, now=False)。这将在第一次调用之前等待四秒钟。

于 2013-08-16T16:34:22.080 回答
1

在网络连接稳定的正常环境中,@habnabit 的方式会起作用,但在现实世界中,连接延迟无法如您所愿估计。这个问题比较好的解决方法,必须在amp客户端这样连接后执行循环调用。

from twisted.protocols.amp import AMP
from twisted.python.log import startLogging, err
from twisted.internet.task import LoopingCall
from twisted.internet import reactor, endpoints
from sys import stdout

import commands

startLogging(stdout)


class MyAMP:
    def __init__(self, host, port):
        destination = endpoints.TCP4ClientEndpoint(reactor, host, port)
        self.protocol = AMP()
        self.d = endpoints.connectProtocol(destination, self.protocol)


def loop (proto, ) :
    return proto.callRemote(commands.get_user, key='Hello world')

def main(host, port):
    def _cb_connected (proto, ) :
        lc = LoopingCall(loop, proto, )
        lc.start(4.0)
        return

    myamp = MyAMP(host, port)
    myamp.d.addCallback(_cb_connected, )
    reactor.run()

    return

main('127.0.0.1', 12345, )
于 2013-08-19T14:22:53.743 回答