LomaxOnTheRun
LomaxOnTheRun

Reputation: 702

Twisted callback loop blocking further data from being recieved

When a callback loop is running in Twisted, it was my impression that the reactor was still able to send/receive data from the server, as it was able to function 'between' the callbacks. However, when I run the script below, it entirely ignores the self.transport.write() line. The server is just the basic echo server Twisted have on their website.

from twisted.internet import reactor, protocol
from twisted.internet.defer import Deferred


class EchoClient(protocol.Protocol):

    deferred = Deferred()

    def connectionMade(self):
        self.deferred.addCallback(self.doThing)
        self.deferred.callback(0)

    def doThing(self, _):
        print 'xxx'
        self.transport.write('Hello, world!')
        self.deferred.addCallback(self.doThing)

    def dataReceived(self, data):
        "As soon as any data is received, write it back."
        print "Server said:", data
        self.transport.loseConnection()


class EchoFactory(protocol.ClientFactory):

    protocol = EchoClient


def main():
    f = EchoFactory()
    reactor.connectTCP('192.168.0.7', 8000, f) # Correctly connected to my server
    reactor.run()

if __name__ == '__main__':
    main()

I expected one, or even a few, 'xxx's being printed, then the server sending an echo of 'Hello, world!' back to me, then more 'xxx's. What I get instead is an infinite scrolling of 'xxx's and no attempt at even sending the 'Hello, world!' to the server. What am I missing/misunderstanding?

Upvotes: 3

Views: 448

Answers (1)

Glyph
Glyph

Reputation: 31860

The problem is that your example is never letting the main loop run.

When a connection is established, you add a callback to self.deferred - I'm not sure what operation self.deferred is supposed to represent, but apparently nothing useful.

Then you immediately (synchronously) call back self.deferred. This goes right away to execute doThing, which calls self.transport.write. This adds some bytes to the outgoing buffer to be sent when the mainloop next runs. Then, in that callback, you immediately (synchronously) add another callback to self.deferred which will run as soon as the current callback is completed. So we go into doThing, which calls self.transport.write. We still haven't written anything yet, let alone read anything to deliver to dataReceived, because we haven't made it back to the main loop. But we add another callback to that Deferred. Which calls doThing again.

This keeps going forever, allocating an infinite amount of memory on the transport as you buffer an ever-increasing amount of outgoing traffic, but never allow the program to return from connectionMade, make it back to the main loop, and wait for writability and readability events.

I don't know how to fix this program because it's not clear what it is that you're trying to do, but whatever it is, this isn't how :).

Upvotes: 2

Related Questions