tags:

views:

40

answers:

1

I'm working on a twisted tutorial just to learn more python and it seems I've ran into a road block here. The doRead() function below is the "callback" of a reactor. What I can't understand is how the except part works.

The way I read the code is that if bytes += self.sock.recv(1024) would've caused a block then it will reach the following part of the code:

if e.args[0] == errno.EWOULDBLOCK:
    break

Then it would've continued to the following:

if not bytes:
    print 'Task %d finished' % self.task_num
    return main.CONNECTION_DONE
else:
    msg = 'Task %d: got %d bytes of poetry from %s'
    print  msg % (self.task_num, len(bytes), self.format_addr())

The tricky part for me is that if it blocked, then bytes variable would've contained nothing and would've printed "finish" but it doesn't. Or at least it would've printed something like "got 0 bytes" but it also doesn't. It almost seems to me like when the code encounters a block from the recv call, it skips the above part completely. Can someone explain why this is happening?

Output is something like this:

Task 1: got 30 bytes of poetry from 127.0.0.1:10000
Task 3: got 10 bytes of poetry from 127.0.0.1:10002
Task 1: got 30 bytes of poetry from 127.0.0.1:10000
Task 3: got 10 bytes of poetry from 127.0.0.1:10002
Task 1: got 30 bytes of poetry from 127.0.0.1:10000
Task 3: got 3 bytes of poetry from 127.0.0.1:10002
Task 1: got 30 bytes of poetry from 127.0.0.1:10000

This is the whole function:

def doRead(self):
    bytes = ''

    while True:
        try:
            bytes += self.sock.recv(1024)
            if not bytes:
                break
        except socket.error, e: # I don't understand this part
            if e.args[0] == errno.EWOULDBLOCK:
                break
            return main.CONNECTION_LOST

    if not bytes:
        print 'Task %d finished' % self.task_num
        return main.CONNECTION_DONE
    else:
        msg = 'Task %d: got %d bytes of poetry from %s'
        print  msg % (self.task_num, len(bytes), self.format_addr())

    self.poem += bytes

The whole module is pasted here: http://pastebin.com/bUnXgbCA

+2  A: 

The point is that method doRead gets called only when the socket is "ready for reading": either it has some data on it, or else it's all done (and then, reading will return 0). So the solution to your problem cannot be in the doRead function -- it's all in the code calling it only when appropriate.

That code is all in the Twisted "reactor", to which the instance of PoetrySocket adds itself in __init__ (via the reactor's addReader method). If you want to understand twisted's mechanisms in real unalloyed depth, you seem to be at the right place, by the way (net of studying twisted's sources themselves, of course;-).

Alex Martelli
Thanks for responding Alex. I'm not really trying to solve any problem, just trying to understand how this works. I'm still not sure what happens right after the the break statement in the except block as it seems like it doesn't reach the "if not bytes:" block at all.
Joseph Arden
@Joseph, so it's never called (in your experiments) on a socket error (which would return the condition in question) but only when the counterpart "just hangs up" (connection lost).
Alex Martelli