2017-12-29 33 views
1

Ich werde einen Dienst hosten, der etwas wie ein Proxy für etwas, das ich ein Client bin, sein wird.Python Twisted besten Weg, um Ereignisse zu einem Proxy zu signalisieren

Also ich möchte, dass mein ProxyService (ein twisted.protocol Server) viele Akteure (Clients) nimmt. Auf der Server-Seite der Dinge, brauche ich eine globale Verbindung (benötigen nur 1 Verbindung zu ihm für alle Clients) zu einem ExistingService (Code, den ich nicht geschrieben habe, und ich bin ein Client dazu).

  • Wenn der ExistingService etwas Interessantes sagt, muss ich es an alle Akteure senden.
  • Wenn ein Schauspieler etwas zu meinem ProxyService sagt, muss ich prüfen, ob es mir gut aussieht. Wenn dies der Fall ist, muss ich den ExistingService informieren.
  • Ich denke, ich weiß, wie das mit globalen Variablen zu lösen, aber nur darüber nachdenken, ob besser Weg, um die Nachrichten zu pushen.

    enter image description here

    +0

    Fragen Sie, wie Sie dies ohne globale Variablen tun? Die Frage nach einem "besseren Weg" ist extrem offen. –

    Antwort

    1

    Sie haben das grundlegende Design gut etabliert. Es ist ein grundlegender "Mann in der Mitte" Ansatz. Es gibt viele Möglichkeiten, es zu implementieren, aber das sollte Ihnen den Einstieg:

    from twisted.internet import endpoints, protocol, reactor 
    
    
    class ProxyClient(protocol.Protocol): 
    
        def connectionMade(self): 
         print('[x] proxy connection made to server') 
         self.factory.proxy_proto = self 
    
        def connectionLost(self, reason): 
         print('[ ] proxy connection to server lost: {0}'.format(reason)) 
         self.factory.proxy_proto = None 
    
        def dataReceived(self, data): 
         print('==> received {0} from server'.format(data)) 
         print('<== transmitting data to all actors') 
         for actor in self.factory.actors: 
          actor.transport.write(data) 
    
    
    class Actor(protocol.Protocol): 
    
        def connectionMade(self): 
         print('[x] actor connection established') 
         self.factory.actors.add(self) 
    
        def connectionLost(self, reason): 
         print('[ ] actor disconnected: {0}'.format(reason)) 
         self.factory.actors.remove(self) 
    
        def dataReceived(self, data): 
         print('==> received {0} from actor'.format(data)) 
         proxy_connection = self.factory.proxy_factory.proxy_proto 
         if proxy_connection is not None: 
          print('<== transmitting data to server through the proxy') 
          proxy_connection.transport.write(data) 
         else: 
          print('[ ] proxy connection to server has not been established') 
    
    
    def setup_servers(): 
        PROXY_HOST = '127.0.0.1' 
        PROXY_PORT = 9000 
        proxy_factory = protocol.ClientFactory() 
        proxy_factory.protocol = ProxyClient 
        proxy_factory.proxy_proto = None 
        proxy_factory.actors = set() 
        proxy_client = endpoints.TCP4ClientEndpoint(reactor, port=PROXY_PORT, host=PROXY_HOST) 
        proxy_client.connect(proxy_factory) 
    
        ACTOR_HOST = '127.0.0.1' 
        ACTOR_PORT = 8000 
        actor_factory = protocol.Factory() 
        actor_factory.protocol = Actor 
        actor_factory.proxy_factory = proxy_factory 
        actor_factory.actors = proxy_factory.actors 
        actor_server = endpoints.TCP4ServerEndpoint(reactor, port=ACTOR_PORT, interface=ACTOR_HOST) 
        actor_server.listen(actor_factory) 
    
    
    def main(): 
        setup_servers() 
        reactor.run() 
    
    
    main() 
    

    Die Kernlogik, die die Daten von dem Server zu Akteuren werden proxied empfangen erlaubt ist proxy_factory.actors = set() und actor_factory.actors = proxy_factory.actors. Die meisten "list-like" Container sind aus Mangel an besseren Wörtern "global" und dieses Beispiel gibt Kontext in die Factory-Objekte jeder Verbindung. Wenn ein Akteur eine Verbindung mit dem Server herstellt, wird ein Actor Protokoll an die set angehängt, und wenn Daten empfangen werden, erhält jedes Protokoll in set die Daten. Siehe die entsprechenden dataReceived() Methoden jedes Protokollobjekts, wie das funktioniert.

    Das obige Beispiel verwendet keine globalen Variablen, aber das heißt nicht, dass Sie sie nicht verwenden könnten. Sehen Sie, wie weit Sie mit dieser Methode der Weitergabe von Variablen, die Kontext in andere Objekte geben können. Außerdem wurden bestimmte Situationen nicht explizit behandelt, z. B. das Zwischenspeichern empfangener Daten für den Fall, dass der Server oder die Akteure noch nicht verbunden waren. Hoffentlich gibt es hier genug Informationen für Sie, um die beste Vorgehensweise für Ihre Bedürfnisse zu bestimmen. Es gibt einige Möglichkeiten, die Syntax zu straffen, um sie auch kürzer zu machen.

    Als eine Randnotiz. Eine Alternative zu globalen Variablen ist picobox. Es ist eine Dependency-Injector-Bibliothek, aber ich habe festgestellt, dass sie die meisten meiner Anforderungen erfüllt, wenn ich Parameter von externen Quellen benötige.

    Verwandte Themen