[Twisted-Python] Create client in Server factory

Phil Mayers p.mayers at imperial.ac.uk
Wed Oct 31 03:49:33 MDT 2012


On 10/31/2012 07:14 AM, Grégoire Leroy wrote:
> Hi,
>
> I have a server who receive data from clients A/B/C (remote machines). I want
> to use a client D (on the same machine than the server) to send this data to
> another server (remote).
>
> The difficulty is, I want to use the same client D connection for any client. I
> don't want open an new connection each time.
>
> First thing I would think is to create the connection in my server factory,
> and use client's methods in my server protocol, for example with
> [...]
> class LocalProxyFactory(Factory):
>          def __init__(self):
>                  f = LocalProxyClientFactory()
>                  reactor.connectTCP("retenodus.net", 4242, f)
>                  reactor.run()

The "reactor.run" is just wrong - remove it.

You need to connect to a server, and share this connection amongst some 
protocols. But you can't control the order in which these connections 
complete, so A/B/C might connect before D is ready.

You've really got two choices - accept the connections from A/B/C but 
have your server protocol "wait" until D is ready - something like this:

from twisted.internet.protocol import ClientCreator

class Server(...):
   def connectionMade(self):
     if self.factory.connD is None:
       self.factory.waitFor(self._ready)
       self.transport.pauseProducing()

   def _ready(self):
     self.transport.resumeProducing()

d_connect = ClientCreator(reactor, DProtocol)

class ServerFactory(...):
   def __init__(self):
     self.connD = None
     self._wait = []
     d_connect.connectTCP(Dhost, port).addCallback(self.dReady)

   def waitFor(self, _cb):
     if self.connD:
       _cb(self.connD)
     else:
       d = defer.Deferred()
       d.addCallback(_cb)
       self._wait.append(d)

   def dReady(self, proto):
     self.connD = proto
     cb = self._wait
     self._wait = []
     for c in cb:
       c.callback(proto)

def main():
   reactor.listenTCP(..., ServerFactory())
   reactor.run()

...or don't start listening until D has connected, like this:

class ServerFactory(...):
   def __init__(self, dProto):
     self.connD = dProto

def startListen(dProto):
   reactor.listenTCP(..., ServerFactory(dProto))

def main():
   d_connect.connectTCP(Dhost, port).addCallback(startListen)
   reactor.run()

The latter is simpler, but which is appropriate depends on your needs.

Note that I've used ClientCreator to get a callback when the connection 
to D is ready - remember that doesn't happen immediately.




More information about the Twisted-Python mailing list