2008-11-24 9 views
23

Ich bin auf der Suche nach einer Möglichkeit, einige Daten regelmäßig über alle Clients an einen TCP-Port zu senden. Ich schaue auf twisted python und ich kenne reactor.callLater. Aber wie verwende ich es, um regelmäßig Daten an alle angeschlossenen Clients zu senden? Die Datensende-Logik befindet sich in der Protokollklasse und wird vom Reaktor nach Bedarf instanziiert. Ich weiß nicht, wie man es vom Reaktor zu allen Protokollinstanzen bindet ...Eine Funktion regelmäßig im verdrehten Protokoll ausführen

Antwort

37

Sie würden dies wahrscheinlich in der Factory für die Verbindungen tun. Die Factory wird nicht automatisch jedes Mal benachrichtigt, wenn eine Verbindung hergestellt oder verloren wird, sodass Sie sie über das Protokoll benachrichtigen können.

Hier ist ein vollständiges Beispiel für die Verwendung von twisted.internet.task.LoopingCall in Verbindung mit einer angepassten Standard-Factory und einem Protokoll, um zu melden, dass alle 10 Sekunden alle 10 Sekunden alle 10 Sekunden vergangen sind.

from twisted.internet import reactor, protocol, task 

class MyProtocol(protocol.Protocol): 
    def connectionMade(self): 
     self.factory.clientConnectionMade(self) 
    def connectionLost(self, reason): 
     self.factory.clientConnectionLost(self) 

class MyFactory(protocol.Factory): 
    protocol = MyProtocol 
    def __init__(self): 
     self.clients = [] 
     self.lc = task.LoopingCall(self.announce) 
     self.lc.start(10) 

    def announce(self): 
     for client in self.clients: 
      client.transport.write("10 seconds has passed\n") 

    def clientConnectionMade(self, client): 
     self.clients.append(client) 

    def clientConnectionLost(self, client): 
     self.clients.remove(client) 

myfactory = MyFactory() 
reactor.listenTCP(9000, myfactory) 
reactor.run() 
+0

Danke! Das hat sehr geholfen. Ich habe versucht, mit dem Senden der Daten in der Protokollklasse fertig zu werden und hatte Probleme damit, keinen Zugriff auf alle Clients zu haben (hatte eine Singleton-Klasse, um alle zu halten!)! Dies in der Fabrik Unterklasse macht so viel mehr Sinn. Ich werde meinen Code umschreiben ... Danke! – Amit

+0

Wie würden Sie einen Test schreiben, um zu verifizieren, dass ein Client sechs Mal pro Minute "* 10 Sekunden vergangen ist"? – Sardathrion

3

Ich könnte mir vorstellen, dass der einfachste Weg das zu tun ist, eine Liste von Clients im Protokoll mit connectionMade und connectionLost im Client und zu verwalten Verwenden Sie dann einen LoopingCall, um jeden Client zum Senden von Daten aufzufordern.

Das fühlt sich ein wenig invasiv an, aber ich denke nicht, dass Sie es tun möchten, ohne dass das Protokoll eine gewisse Kontrolle über die Übertragung/den Empfang hat. Natürlich müsste ich deinen Code sehen, um wirklich zu wissen, wie er gut passt. Hast du einen GitHub Link? :)

+0

Ich habe die erste Version funktioniert. Der reactor.callLater kann überall aufgerufen werden, also habe ich ihn von connectionMade() aufgerufen. Jetzt besteht das Problem jedoch darin, dass jede Verbindung ihren eigenen Timer und Daten erhält. Ich hätte gerne einen einzigen Timer und Daten. (wie eine Sendung) ... – Amit