Twisted:使用 pyglet-twisted 时如何从 EndPoint 调用 Deferred

Posted

技术标签:

【中文标题】Twisted:使用 pyglet-twisted 时如何从 EndPoint 调用 Deferred【英文标题】:Twisted: How is Deferred called from EndPoint when using pyglet-twisted 【发布时间】:2013-02-07 20:15:42 【问题描述】:

以下代码取自 Twisted 关于 AMP 的文档 (link)。当回调被添加到 d 时,会自动添加一个“协议”参数,并且在调用 reactor.run() 时会自动运行 deferred。

def connect():
    endpoint = TCP4ClientEndpoint(reactor, "127.0.0.1", 8750)
    factory = Factory()
    factory.protocol = AMP
    return endpoint.connect(factory)

d = connect()
def connected(protocol):
    return protocol.callRemote(
        RegisterUser,
        username=u'alice'
d.addCallback(connected)

reactor.run()

在我的代码中,一切都完全相同,除了我一直在使用 pyglet-twisted (link) 和 cocos2d,所以我不能调用 reactor.run(),因为反应器与申请。

如果我调用 reactor.run(),我会收到一条错误消息,指出反应器已经在运行。

如果我不这样做,deferred 似乎不会被调用。

我一直在尝试使用 reactor.callLater、reactor.callWhenRunning 来调用它,但两者都需要一个参数。传入 None 不起作用。

所以我的问题是,我应该如何在不调用 reactor.run() 的情况下使这个延迟运行。

谢谢!

【问题讨论】:

【参考方案1】:

没有一个正在运行的反应器,Twisted 的 API 很少能成功。反应器负责执行 I/O。您必须有一个正在运行的反应器才能建立连接(无论您使用的是端点对象还是其他 API)。

据我所知,pyglet 集成反应器不会自动启动。有些东西必须调用它的run 方法。您的问题表明您没有调用它,所以我很好奇 是什么 调用它。

当我修改您的示例以使其完整且可运行并添加错误报告时,如下所示:

from pygletreactor import install
install()

from twisted.internet import reactor
from twisted.internet.endpoints import TCP4ClientEndpoint
from twisted.internet.protocol import Factory
from twisted.protocols.amp import AMP
from twisted.python.log import err

def connect():
    endpoint = TCP4ClientEndpoint(reactor, "127.0.0.1", 8750)
    factory = Factory()
    factory.protocol = AMP
    return endpoint.connect(factory)

d = connect()
def connected(protocol):
    return protocol.callRemote(
        RegisterUser,
        username=u'alice')
d.addCallback(connected)
d.addErrback(err)

reactor.run()

然后我得到了我期望的行为,即尝试连接然后失败(因为我没有在任何地方运行 AMP 服务器):

Unhandled Error
Traceback (most recent call last):
Failure: twisted.internet.error.ConnectionRefusedError: Connection was refused by other side: 111: Connection refused.

也许您可以将其与您的完整程序进行比较,并找出重要的区别。

【讨论】:

谢谢!我忘了提到我修改了 pyglet 以调用 reactor.run()。我又看了看这个问题,结果发现问题在于 cocos2d 被硬编码以使用 pyglet 的事件循环的方式,所以 pygletreactor 中的循环没有被调用。【参考方案2】:

经过更多研究,我发现从endpoint.connect()返回的deferred没有被调用的原因是cocos2d的一个错误。

cocos.director 的底部,其中pyglet.app.event_loop 被分配处理director.event = event_loop.event 行中的导演事件。

这需要改为使用pygletreactoreventloop。所以上面的代码需要改成如下:

import pygletreactor
event_loop = pygletreactor.EventLoop()
director = Director()
director.event = event_loop.event

【讨论】:

以上是关于Twisted:使用 pyglet-twisted 时如何从 EndPoint 调用 Deferred的主要内容,如果未能解决你的问题,请参考以下文章

从 Twisted 客户端发送到 Twisted 服务器,只有这一种方式

如何使用 Twisted 与进程通信?

Twisted 框架 初印象

结合使用WebSphere MQ和Twisted

第三部分:初步认识Twisted

使用 msn 协议运行 twisted.words 示例时出现问题