FAQ
Hi,

I'm writing and testing an asyncore-based server. Unfortunately, it
doesn't seem to work. The code below is based on the official docs and
examples, and starts a listening and sending dispatcher, where the
sending dispatcher connects and sends a message to the listener - yet
Handler.handle_read() never gets called, and I'm not sure why. Any
ideas?

Thanks, D.


import asyncore, socket, sys

COMM_PORT = 9345

class Handler(asyncore.dispatcher):
def handle_read(self):
print 'This never prints'

class Listener(asyncore.dispatcher):
def __init__(self, port=COMM_PORT):
asyncore.dispatcher.__init__(self)
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
self.set_reuse_addr()
self.bind(('', port))
self.listen(5)

def handle_accept(self):
client, addr = self.accept()
print 'This prints.'
return Handler(client)

class Sender(asyncore.dispatcher):
def __init__(self, host):
asyncore.dispatcher.__init__(self)
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
self.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.connect( (host, COMM_PORT) )
self.buffer = 'Msg\r\n'

def handle_connect(self):
pass

def writable(self):
return len(self.buffer) > 0

def handle_write(self):
sent = self.send(self.buffer)
self.buffer = self.buffer[sent:]

def test_communication():
from multiprocessing import Process
def listener():
l = Listener()
asyncore.loop(timeout, count=1)
lis = Process(target=listener)
lis.start()
def sender():
s = Sender('localhost')
asyncore.loop(timeout, count=1)
sen = Process(target=sender)
sen.start()
lis.join()

test_communication()

Search Discussions

  • Jean-Paul Calderone at Apr 20, 2011 at 8:01 pm

    On Apr 20, 12:25?pm, Dun Peal wrote:
    Hi,

    I'm writing and testing an asyncore-based server. Unfortunately, it
    doesn't seem to work. The code below is based on the official docs and
    examples, and starts a listening and sending dispatcher, where the
    sending dispatcher connects and sends a message to the listener - yet
    Handler.handle_read() never gets called, and I'm not sure why. Any
    ideas?

    Thanks, D.

    import asyncore, socket, sys

    COMM_PORT = 9345

    class Handler(asyncore.dispatcher):
    ? ? def handle_read(self):
    ? ? ? ? print 'This never prints'

    class Listener(asyncore.dispatcher):
    ? ? def __init__(self, port=COMM_PORT):
    ? ? ? ? asyncore.dispatcher.__init__(self)
    ? ? ? ? self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
    ? ? ? ? self.set_reuse_addr()
    ? ? ? ? self.bind(('', port))
    ? ? ? ? self.listen(5)

    ? ? def handle_accept(self):
    ? ? ? ? client, addr = self.accept()
    ? ? ? ? print 'This prints.'
    ? ? ? ? return Handler(client)

    class Sender(asyncore.dispatcher):
    ? ? def __init__(self, host):
    ? ? ? ? asyncore.dispatcher.__init__(self)
    ? ? ? ? self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
    ? ? ? ? self.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    ? ? ? ? self.connect( (host, COMM_PORT) )
    ? ? ? ? self.buffer = 'Msg\r\n'

    ? ? def handle_connect(self):
    ? ? ? ? pass

    ? ? def writable(self):
    ? ? ? ? return len(self.buffer) > 0

    ? ? def handle_write(self):
    ? ? ? ? sent = self.send(self.buffer)
    ? ? ? ? self.buffer = self.buffer[sent:]

    def test_communication():
    ? ? from multiprocessing import Process
    ? ? def listener():
    ? ? ? ? l = Listener()
    ? ? ? ? asyncore.loop(timeout, count=1)
    ? ? lis = Process(target=listener)
    ? ? lis.start()
    ? ? def sender():
    ? ? ? ? s = Sender('localhost')
    ? ? ? ? asyncore.loop(timeout, count=1)
    ? ? sen = Process(target=sender)
    ? ? sen.start()
    ? ? lis.join()

    test_communication()
    You didn't let the program run long enough for the later events to
    happen. loop(count=1) basically means one I/O event will be processed
    - in the case of your example, that's an accept(). Then asyncore is
    done and it never gets to your custom handle_read.

    So you can try passing a higher count to loop, or you can add your own
    loop around the loop call. Or you can switch to Twisted which
    actually makes testing a lot easier than this - no need to spawn
    multiple processes or call accept or recv yourself. Here's a somewhat
    equivalent Twisted-based version of your program:

    from twisted.internet.protocol import ServerFactory, Protocol
    from twisted.internet import reactor

    factory = ServerFactory()
    factory.protocol = Protocol

    reactor.listenTCP(0, factory)
    reactor.run()

    It's hard to write the equivalent unit test, because the test you
    wrote for the asyncore-based version is testing lots of low level
    details which, as you can see, don't actually appear in the Twisted-
    based version because Twisted does them for you already. However,
    once you get past all that low-level stuff and get to the part where
    you actually implement some of your application logic, you might have
    tests for your protocol implementation that look something like this:

    from twisted.trial.unittest import TestCase
    from twisted.test.proto_helpers import StringTransport

    from yourapp import Handler # Or a better name

    class HandlerTests(TestCase):
    def test_someMessage(self):
    """
    When the "X" message is received, the "Y" response is sent
    back.
    """
    transport = StringTransport()
    protocol = Handler()
    protocol.makeConnection(transport)
    protocol.dataReceived("X")
    self.assertEqual(transport.value(), "Y")

    Hope this helps,
    Jean-Paul
  • Dun Peal at Apr 20, 2011 at 9:17 pm

    On Apr 20, 3:01?pm, Jean-Paul Calderone wrote:
    You didn't let the program run long enough for the later events to
    happen. ?loop(count=1) basically means one I/O event will be processed
    - in the case of your example, that's an accept(). ?Then asyncore is
    done and it never gets to your custom handle_read.
    Wow, a response from a Twisted founder and core developer =)

    You were right, of course. Incrementing the count to 2 on the
    asyncore.loop() calls makes the snippet work as expected.

    I'd definitely rather use Twisted. It's unclear why transmitting a
    bytestream message between two servers should require low-level socket
    incantations such as `self.create_socket(socket.AF_INET,
    socket.SOCK_STREAM)` or `self.setsockopt(socket.SOL_SOCKET,
    socket.SO_REUSEADDR, 1)`. The stdlib should offer a higher-level
    asynchronous communication abstraction to support such a
    straightforward usecase. Twisted does provide that, but my humble
    needs can't justify the extra dependency cost.

    Thanks a lot, D.

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
grouppython-list @
categoriespython
postedApr 20, '11 at 4:25p
activeApr 20, '11 at 9:17p
posts3
users2
websitepython.org

2 users in discussion

Dun Peal: 2 posts Jean-Paul Calderone: 1 post

People

Translate

site design / logo © 2022 Grokbase