2010-07-21 95 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