【问题标题】:Connecting twice with twisted - how to do that correctly?用twisted 连接两次——如何正确地做到这一点?
【发布时间】:2009-12-30 08:44:44
【问题描述】:

我想使用 twisted(和 StarPy,它是 asterisk ami 的协议实现)连接到 asterisk 服务器。应用程序在那里启动传出传真。我发现了一些关于我的问题的提示,但我不知道如何正确处理。

第一份传真已正确发送。

问题是,如果我为 第二次,应用程序保持 挂在主循环中。

我知道我可能不会在这里这样做:

from starpy import manager
from twisted.internet import reactor

def main():
    f = manager.AMIFactory(cUser, cPass)
    print "Login"
    df = f.login(cServer, cPort)

    def onLogin(protocol):
        print "Logoff again"
        df = protocol.logoff()

        def onLogoff( result ):
            print "Logoff erfolgt"
            reactor.stop()

        return df.addCallbacks( onLogoff, onLogoff )

    def onFailure( reason ):
        print "Login failed"
        print reason.getTraceback()

    df.addCallbacks( onLogin, onFailure )
    return df

if __name__ == "__main__":
    reactor.callWhenRunning( main )
    reactor.run(installSignalHandlers=0)
    print "runned the first time"

    reactor.callWhenRunning( main )
    reactor.run(installSignalHandlers=0)
    print "will never reach this point"

我简化了代码 - 它只是再次登录 + 注销。它永远不会从第二个 reactor.run() 调用返回。

这是如何正确完成的?我被困在这里 - 在此先感谢。

最好的问候, 弗洛里安。

【问题讨论】:

    标签: twisted


    【解决方案1】:

    正如 iny 所说,您只需拨打reactor.runreactor.stop 即可完成所有操作。

    如果我们考虑您发布的示例代码,我们会发现它采取了以下步骤:

    1. 启动反应器
      • 连接、发送传真、断开连接
      • 停止反应器
      • 启动反应堆
      • 连接、发送传真、断开连接
      • 停止反应器

    如果我们只删除步骤 3 和 4,那么程序实际上会做一件非常合理的事情。

    这是您实施第 3 步的方式:

    def onLogoff( result ):
        print "Logoff erfolgt"
        reactor.stop()
    

    这导致对 reactor.run 的第一次调用返回,为您执行第 4 步扫清了道路:

    reactor.callWhenRunning( main )
    reactor.run(installSignalHandlers=0)
    

    因此,这里的总体思路是直接跳到第 5 步,而不是执行第 3 步和第 4 步。考虑一下如果您像这样重新定义 onLogoff 会发生什么:

    def onLogoff( result ):
        print "Logoff erfolgt"
        main()
    

    并删除示例的最后三行。这实际上会给您一个无限循环,因为相同的onLogoff 在第二次断开连接后运行并开始第三次连接。但是,您可以使用 main 函数的参数来控制重启行为。

    一旦这变得有意义,您可能需要考虑将重试注销从main 函数中移出,并移到__main__ 块中定义的回调中。这是 Deferreds 强大功能的重要组成部分:它允许您在事件源的实现(在本例中为您的传真发送函数)和处理结果事件的代码(发送第二个传真,或退出,在这种情况下)。

    【讨论】:

    • 好的,你给我个主意。我必须再次通过 Deferreds 文档工作。也许这会阻止我把头撞到墙上。有没有办法在不停止反应堆的情况下关闭传出的 TCP 连接?我不喜欢一直打开 TCP-Session 的想法……谢谢。
    【解决方案2】:

    感谢您的回答,我现在还没有实施解决方案,但我知道我现在该怎么做...

    这里是我学到的东西的简短摘要。

    首先,简而言之 - 我在扭曲时遇到的问题:

    1. 我不了解twisted 的异步基础知识。我在 gui-frameworks 中使用了类似的东西,但很长时间没有看到好处。
    2. 其次,我试图多次考虑事件循环的同步调用。这在我看来是必要的,因为我一次不能使用超过一条传出传真线路。因为 twisted 的事件循环不可重新启动,所以这是没有选择的。正如我在文档中看到的那样,“deferToThread”可以帮助我,但我认为这不是最好的解决方案。

    在我的概念中,我解决了这些问题:

    我需要重新思考,但一旦你得到它,它看起来真的很容易。

    感谢 iny 和 Jean-Paul Calderone 的帮助。

    【讨论】:

      【解决方案3】:

      您无法重新启动反应堆。换句话说,您只能调用 reactor.run() 一次。

      而是可以在一次反应器运行中完成您需要的一切。

      【讨论】:

      • 是的,这也是我在网上找到的。但我无法弄清楚我需要如何处理这个问题。也许你可以指出我正确的方向: * 我什么时候启动反应堆?在应用程序启动时或我第一次使用它时? * 我怎样才能要求一个反应堆 1. 连接/2.发送传真/3。多次松开连接?我被困住了。我投入了数小时开发和阅读手册 - 我只是找不到答案......提前致谢。
      【解决方案4】:

      如果您仍在寻找解决方案...我遇到了同样的问题。我有一个使用 Twisted 在远程服务器上执行程序的脚本。我需要一种从 django 应用程序中同步运行该脚本的方法。我最终做的是让我的 Twisted 脚本调用远程服务器并打印到标准输出。然后在我的 Django 应用程序中,我通过 subprocess.Popen 执行该脚本并设置 stdout=PIPE,以便我可以捕获 Twisted 脚本的输出并在我的 Django 应用程序中使用它。

      这不是很理想,并且几乎违背了 Twisted 的目的,但这超越了“无法第二次调用 reactor.run(),因为 Twisted 脚本每次都在它自己的进程中运行.

      这确实对我很有帮助,而且听起来与您所处的情况非常相似。我希望这会有所帮助。祝你好运。 (如果您认为有帮助,我可以发布一些代码示例,请告诉我)。

      【讨论】:

      • 谢谢,我不喜欢这个。我唯一不喜欢twisted的是,它(在我的配置中)保持连接打开而不是关闭它并等待再次需要它。我不明白为什么这个设计有意义。异步确实如此——即使我需要一些时间来理解。还是谢谢。
      • 这就是我使用子进程的原因,当子进程存在时,连接关闭。当我再次调用我的子进程时,它会打开它并在完成后关闭。
      • 如果您想在 Twisted 中断开连接,您可以随时致电 transport.loseConnection()。 Twisted 保持连接打开的原因是您没有要求关闭它!
      猜你喜欢
      • 1970-01-01
      • 2020-02-16
      • 2012-08-22
      • 1970-01-01
      • 2017-02-24
      • 1970-01-01
      • 2011-02-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多