# This is the asynchronous Get Poetry Now! client.

import datetime, errno, optparse, select, socket


def parse_args():
    usage = """usage: %prog [options] [hostname]:port ...

This is the Get Poetry Now! client, asynchronous edition.
Run it like this:

  python get-poetry.py port1 port2 port3 ...

If you are in the base directory of the twisted-intro package,
you could run it like this:

  python async-client/get-poetry.py 10001 10002 10003

to grab poetry from servers on ports 10001, 10002, and 10003.

Of course, there need to be servers listening on those ports
for that to work.
"""

    parser = optparse.OptionParser(usage)

    _, addresses = parser.parse_args()

    if not addresses:
        print parser.format_help()
        parser.exit()

    def parse_address(addr):
        if ':' not in addr:
            host = '127.0.0.1'
            port = addr
        else:
            host, port = addr.split(':', 1)

        if not port.isdigit():
            parser.error('Ports must be integers.')

        return host, int(port)

    return map(parse_address, addresses)


def get_poetry(sockets):
    """Download poety from all the given sockets."""

    poems = dict.fromkeys(sockets, '') # socket -> accumulated poem

    # socket -> task numbers
    sock2task = dict([(s, i + 1) for i, s in enumerate(sockets)])

    sockets = list(sockets) # make a copy

    # we go around this loop until we've gotten all the poetry
    # from all the sockets. This is the 'reactor loop'.

    while sockets:
        # this select call blocks until one or more of the
        # sockets is ready for read I/O
        rlist, _, _ = select.select(sockets, [], [])

        # rlist is the list of sockets with data ready to read

        for sock in rlist:
            data = ''

            while True:
                try:
                    data += sock.recv(1024)
                    if not data:
                        break
                except socket.error, e:
                    if e.args[0] == errno.EWOULDBLOCK:
                        # this error code means we would have
                        # blocked if the socket was blocking.
                        # instead we skip to the next socket
                        break
                    raise

            # Each execution of this inner loop corresponds to
            # working on one asynchronous task in Figure 3 here:
            # http://krondo.com/?p=1209#figure3

            task_num = sock2task[sock]
            addr_fmt = format_address(sock.getpeername())

            if not data:
                sockets.remove(sock)
                sock.close()
                print 'Task %d finished' % task_num
            else:
                msg = 'Task %d: got %d bytes of poetry from %s'
                print  msg % (task_num, len(data), addr_fmt)

            poems[sock] += data

    return poems


def connect(address):
    """Connect to the given server and return a non-blocking socket."""

    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.connect(address)
    sock.setblocking(0)
    return sock


def format_address(address):
    host, port = address
    return '%s:%s' % (host or '127.0.0.1', port)


def main():
    addresses = parse_args()

    start = datetime.datetime.now()

    sockets = map(connect, addresses)

    poems = get_poetry(sockets)

    elapsed = datetime.datetime.now() - start

    for i, sock in enumerate(sockets):
        print 'Task %d: %d bytes of poetry' % (i + 1, len(poems[sock]))

    print 'Got %d poems in %s' % (len(addresses), elapsed)


if __name__ == '__main__':
    main()

@@ -1757,59 +1757,8 @@
 st:%0A
-            data = ''%0A%0A            while True:%0A    
     
@@ -1790,18 +1790,13 @@
     
-   
- 
 data 
-+
 = so
@@ -1813,75 +1813,8 @@
 24)%0A
-                    if not data:%0A                        break%0A    
     
@@ -1845,20 +1845,16 @@
 ror, e:%0A
-    
         
@@ -1912,28 +1912,24 @@
             
-    
 # this error
@@ -1954,20 +1954,16 @@
 ld have%0A
-    
         
@@ -2032,20 +2032,16 @@
         
-   
- 
 # instea
@@ -2093,17 +2093,39 @@
     
-    break
+data = ''%0A                else:
 %0A   
@@ -2367,66 +2367,8 @@
 ock%5D
-%0A            addr_fmt = format_address(sock.getpeername())
 %0A%0A  
@@ -2508,16 +2508,16 @@
 ask_num%0A
-
         
@@ -2518,32 +2518,94 @@
           else:%0A
+                addr_fmt = format_address(sock.getpeername())%0A
                 

Remove inner loop, avoid potential infinite loop. Thanks Alexei Romanoff.