2010-07-21 84 views
6

具有扭曲的为期1天的经验,我尝试安排消息回复发送到TCP客户端:Python扭曲:如何安排?

import os, sys, time 
from twisted.internet import protocol, reactor 

self.scenario = [(1, "Message after 1 sec!"), (4, "This after 4 secs"), (2, "End final after 2 secs")] 
for timeout, data in self.scenario: 
     reactor.callLater(timeout, self.sendata, data) 
     print "waited %d time, sent %s\n"%(timeout, data) 

现在,它发送的消息,但我有2个问题:
1)“超时”是从去“现在“,并且我想在每个前一个任务完成之后对其进行计数(之前的消息已发送)
2)我不知道如何在所有消息发送后关闭连接。如果我在callLater之后放置self.transport.loseConnection(),它立即关闭连接。

在之前的尝试中,我没有使用reactor.callLater,但只有self.transport.write()time.sleep(n)for循环中。在这种情况下,所有消息在所有超时过后都会一起发送......不是我想要的。
目的是等待客户端连接,等待timeout1并发送message1,等待timeout2并发送message2,等等。最后的消息 - 关闭连接之后。

回答

8

与Twisted一起工作时要认识到的重要一点是什么也没有等到。当您致电reactor.callLater()时,您要求反应堆稍后拨打,而不是现在。该通话立即结束(通话结束后,已执行之前)。因此,您的print声明是谎言:您没有等待timeout时间;你根本没有等。

您可以通过多种方式解决问题,使用哪个取决于您实际需要的内容。如果您希望第二个任务在第一个任务开始后四秒开始,您可以简单地将第一个任务的延迟(您的timeout变量)添加到第二个任务的延迟中。不过,第一项任务可能无法准确开始,它可能会在稍后开始,如果Twisted太忙,无法尽快启动它。此外,如果您的任务需要很长时间,则在第二个任务开始之前可能不会完成任务。

更常见的方法是让第一个任务安排第二个任务,而不是马上安排第二个任务。您可以在第一个任务结束后四秒(通过在第一个任务结束时调用reactor.callLater())或第一个任务开始后四秒钟(通过在第一个任务的开始处调用reactor.callLater())安排它,或执行更多复杂的计算来确定何时开始,跟踪已用时间。

当您在Twisted等待中没有意识到任何事情时,处理完成所有计划任务时关闭连接变得非常简单:您只需将最后一个任务调用self.transport.loseConnection()即可。对于更复杂的情况,您可能希望将Deferred连锁在一起,或者在所有未完成任务完成时使用DeferredList执行loseConnection(),即使它们并非严格按顺序执行。

+0

谢谢,现在我明白了为什么“睡大觉”,没有工作。你能举一个例子,在前面reactor.callLater()的末尾安排reactor.callLater()吗? – DominiCane 2010-07-22 05:12:40

+0

只需定义一个调用'self.sendata(data)'的函数,然后为下一个回调调用'reactor.callLater()',并将该函数传递给第一个'reactor.callLater()'而不是'self.sendata ' – 2010-07-22 18:26:53

4

这笔交易的最终解决方案..

import os, sys, time 
from twisted.internet import protocol, reactor 
import itertools 

def sendScenario(self): 
    def sendelayed(d): 
     self.sendata(d) 
     self.factory.out_dump.write(d) 
     try: 
      timeout, data = next(self.sc) 
      reactor.callLater(timeout, sendelayed, data) 
     except StopIteration: 
      print "Scenario completed!" 
      self.transport.loseConnection() 

    self.scenario = [(1, "Message after 1 sec!"), (4, "This after 4 secs"), (2, "End final after 2 secs")] 
    self.sc = iter(self.scenario) 
    timeout, data = next(self.sc) 
    reactor.callLater(timeout, sendelayed, data) 
+0

Just fyi:'self.scenario .__ iter __()' - >'iter(self.scenario)','self.sc.next()' - >'next(self.sc)'(从2.6开始) – 2010-07-23 13:15:10

+0

谢谢,改了。 – DominiCane 2010-07-25 12:28:40