Twisted Python factory methods aren't getting called when using reactor wrappers

663 views Asked by At

I have a simple client / server setup. Here's the client code:

from twisted.internet import reactor
from twisted.internet import protocol
from twisted.internet.endpoints import TCP4ClientEndpoint

class MyProtocol(protocol.Protocol):

    def connectionMade(self):
        print "Hello!"

    def dataReceived(self, data):
        print data

class MyProtocolFactory(protocol.ClientFactory):

    def startedConnecting(self, connector):
        print "Starting to connect!"

    def buildProtocol(self, addr):
        return MyProtocol()

    def clientConnectionLost(self, connector, reason):
        print "Lost connection, reason = %s" % reason

    def clientConnectionFailed(self, connector, reason):
        print "Connection failed, reason = %s" % reason
        reactor.stop()

endpoint = TCP4ClientEndpoint(reactor, "127.0.0.1", 54321, timeout=5)
endpoint.connect(MyProtocolFactory())
reactor.run()

For some reason, this client will connect to the server and the protocol works correctly (I can see "Hello!" printed, along with data sent by the server upon a successful connection), but it won't call any of the protocol factory methods. startedConnecting doesn't get called, and if I stop the server, I don't see clientConnectionLost get called. If I try to run the client before the server has started, I would also expect to see clientConnectionFailed get called.

Here's the strange part...If I change the last 3 lines in the code above to the following:

reactor.connectTCP("127.0.0.1", 54321, MyProtocolFactory())
reactor.run()

Then everything works as expected, and all methods get called in all of the cases outlined above.

My understanding of endpoints is that they wrap "connectTCP" (among others) with additional behaviour, but I can't figure out why it works in the second code snippet, but not the first.

Any ideas?

2

There are 2 answers

5
Jean-Paul Calderone On BEST ANSWER

The client endpoint interface does not call the extra connection-state notification methods of ClientFactory.

So, while endpoints do in some sense "wrap" connectTCP et al, it's not true that they have the exact same behavior as using those lower-level methods.

With endpoints, the factory's job is to provide protocol instances. The factory is no longer responsible for other aspects of connection management.

0
Novark On

Additional note to supplement my discussion above:

If you’ve used ClientFactory before, keep in mind that the connect method takes a Factory, not a ClientFactory. Even if you pass a ClientFactory to endpoint.connect, its clientConnectionFailed and clientConnectionLost methods will not be called. In particular, clients that extend ReconnectingClientFactory won’t reconnect. The next section describes how to set up reconnecting clients on endpoints.

From the endpoint docs found here: http://twistedmatrix.com/documents/current/core/howto/endpoints.html