views:

143

answers:

1

I'm trying to just make a simple asyncore example where one socket is the sender and one is the receiver. For some reason, the handle_read() on the receiver is never called so I never get the 'test' data. Anyone know why? This is my first shot at asyncore, so it's probably something extremely simple.

import asyncore, socket, pdb, random

class Sender(asyncore.dispatcher):
    def __init__(self):
        asyncore.dispatcher.__init__(self)
        self.create_socket(socket.AF_INET, socket.SOCK_STREAM)

    def handle_connect(self):
        print ('first connect')

    def writable(self):
        True

    def readable(self):
        return False

    def handle_write(self):
        pass

    def handle_close(self):
        self.close()

class Receiver(asyncore.dispatcher):
    def __init__(self):
        asyncore.dispatcher.__init__(self)
        self.create_socket(socket.AF_INET, socket.SOCK_STREAM)

    def handle_connect(self):
        print ('first connect')

    def readable(self):
        return True

    def handle_read(self):
        print 'reading'

    def handle_write(self):
        print 'write'

    def handle_accept(self):
        self.conn_sock, addr = self.accept()
        print 'accepted'

    def handle_close(self):
        self.close()
a = Sender()
b = Receiver()
addr = ('localhost', 12344)
b.bind(addr)
b.listen(1)
a.connect(addr)
asyncore.loop()
a.send('test')
+1  A: 

asyncore.loop does not terminate, so the a.send doesn't happen, since you've coded it to happen in line after the exit of asyncore.loop.

Once this is fixed, you run into the problem that you're running sender and receiver within a single thread and process, so unless you take very delicate steps to ensure everything happens in the right order, you ARE going to get deadlocked. asyncore is of course meant to be used among processes running separately, so the problem just doesn't appear in normal, real-world uses. If you're curious about exactly where you're deadlocking, make your own copy of asyncore and pepper it with print statements, or, try

python -m trace -t ast.py

Unfortunately, the latter gives a lot of output and doesn't show crucial variables' values. so, while painless and non-invasive to try, it's far less helpful than a few strategically placed prints (e.g., the r and w fd lists just before and after each select).

I believe (but haven't debugged it in depth, since it's an unrealistic scenario anyway) that the select triggers only once (because you have both the accept/connect and the writing of bytes to the socket happen before the first select, they end up "collapsed" into a single event), but the handling of that one event can't know about the collapsing (wouldn't happen in normal use!-) so it only deals with the accept/connect. But if you take the time to debug in greater depth you may no doubt understand this anomalous scenario better!

Alex Martelli
Okay, I've added the send command into Sender's handle_write function: handle_write(self): self.send('test')Shouldn't this be running in the loop? Nothing happens.
victor
What action do you expect to trigger `handle_write()`? Otherwise `send()` in it will never be called.
Denis Otkidach
@victor, edited my answer to provide more information.
Alex Martelli