2012-02-29 63 views
3

我在寫一個Python程序,它將使用Twisted連接到一個TCP服務器。套接字另一端的服務器可能運行兩種可能的協議之一(protoA或protoB),但我不知道它是哪一種協議,直到我發起連接並「詢問」服務器是哪種協議用過的。我能夠確定連接後正在使用哪個版本的協議(protoA或protoB),但我不知道它提前。Twisted:我如何識別初始連接上的協議,然後委託給相應的協議實現?

很明顯,一種解決方案是在我的扭曲的協議派生類中有很多特殊代碼 - 即如果protoA這樣做,elif protoB會做其他事情。但是,我希望能夠在兩個獨立的協議實現中保留兩個獨立協議的代碼(儘管它們可能通過基類共享一些功能)。由於該協議的兩個版本都涉及維護狀態,因此必須將兩個版本混合到同一個類中,這很快會讓人感到困惑。

我該怎麼做?有沒有辦法在工廠實現中做最初的「協議識別」步驟,然後實例化正確的協議派生?

回答

4

不是在整個協議實現中混合決策邏輯,而是將它放在一個地方。

class DecisionProtocol(Protocol): 
    def connectionMade(self): 
     self.state = "undecided" 

    def makeProgressTowardsDecision(self, bytes): 
     # Do some stuff, eventually return ProtoA() or ProtoB() 

    def dataReceived(self, bytes): 
     if self.state == "undecided": 
      proto, extra = self.makeProgressTowardsDecision(bytes) 
      if proto is not None: 
       self.state = "decided" 
       self.decidedOnProtocol = proto 
       self.decidedOnProtocol.makeConnection(self.transport) 
       if extra: 
        self.decidedOnProtocol.dataReceived(extra) 

     else: 
      self.decidedOnProtocol.dataReceived(bytes) 

    def connectionLost(self, reason): 
     if self.state == "decided": 
      self.decidedOnProtocol.connectionLost(reason) 

最終你可以用少一點的樣板來實現這一點:http://tm.tl/3204/

1

這是很容易用一些神奇的完成。

class MagicProtocol(Protocol): 
    ... 
    def dataReceived(self, data): 
     protocol = self.decideProtocol(data) 
     for attr in dir(protocol): 
      setattr(self, attr, getattr(protocol, attr)) 

這是醜陋的,但它會有效地切換爲選擇協議的魔術協議。