使用twisted连接两次-如何正确连接?

使用twisted连接两次-如何正确连接?,twisted,Twisted,我想使用twisted(和StarPy,它是asterisk ami的协议实现)连接到asterisk服务器。应用程序在那里启动传出传真。我发现了一些关于我的问题的提示,但我不知道如何正确处理这个问题 第一份传真发送正确 问题是,如果我打电话给twisted 第二次,应用程序保持 挂在主回路中 我知道我可能不会在这里这样做: from starpy import manager from twisted.internet import reactor def main(): f = m

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

第一份传真发送正确

问题是,如果我打电话给twisted 第二次,应用程序保持 挂在主回路中

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

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()调用返回

如何正确地做到这一点?我被困在这里了-提前谢谢

致以最良好的祝愿,
Florian.

你不能重启反应堆。换句话说,您只能调用reactor.run()一次


相反,您可以在一次反应堆运行中完成所有需要的操作。

正如iny所说,您只需一次调用
反应堆。运行
反应堆。停止

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

  • 启动反应堆
    • 连接、发送传真、断开连接
    • 停止反应堆
    • 启动反应堆
    • 连接、发送传真、断开连接
    • 停止反应堆
  • 如果我们只删除第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
    函数,并移到
    \uuuu main\uuu
    块中定义的回调中。这是延迟功能的很大一部分:它使您能够在事件源的实现(在本例中是传真发送功能)和处理结果事件的代码(在本例中是发送第二份传真或退出)之间保持适当的分离。

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

    这里是我学到的东西的简短总结

    首先,简而言之——我在twisted上遇到的问题:

  • 我不理解twisted的异步基础知识。我在gui框架中使用了类似的东西,但很长一段时间没有看到它的好处
  • 其次,我多次尝试考虑事件循环的同步调用。在我看来,这是必要的,因为我一次只能使用一条外发传真线。由于twisted的事件循环不可重新启动,因此没有选项。正如我在文档中所读到的,“deferToThread”可以在这里帮助我,但我认为这不是最好的解决方案
  • 在我的观念中,我解决了这些问题:

    • 使用defer.DeferredSemaphore(),允许我将并发限制为1。 我在这里找到了一个例子:
    • 随时给twisted打电话,让延期者做工作(发送传真)
    • 将传真状态写入数据库并发送回执邮件将从延迟者调用
    我需要很多的重新思考,但一旦你得到它,它看起来真的很容易


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

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

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


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

    是的,这也是我在网上发现的。但我无法弄清楚我需要如何处理这个问题。也许你可以给我指出正确的方向:*我什么时候启动反应器?应用程序启动时还是第一次使用时?*我如何让一个反应器1.连接/2.发送传真/3.多次断开连接?我卡住了。我投资了ed hours开发和阅读手册-我只是找不到答案…提前谢谢。好吧,你给我一个想法。我必须再次阅读延迟的文档。也许这会阻止我撞墙。有没有办法在不停止反应堆的情况下关闭传出TCP连接?我不喜欢这个想法TCP会话一直处于打开状态…谢谢。谢谢,我不喜欢这个。twisted中我唯一不喜欢的是,它(在我的配置中)保持连接打开,而不是关闭它并等待再次需要它。我不明白为什么这种设计有意义。异步是有意义的-即使我需要一些时间来理解。无论如何,谢谢。这就是为什么我使用子进程,当子进程存在时,连接关闭。当我再次调用我的子进程时,它会打开并关闭它完成后关闭。您始终可以调用
    transport.loseConnection()