Path: csiph.com!x330-a1.tempe.blueboxinc.net!usenet.pasdenom.info!news.albasani.net!feeder.news-service.com!postnews.google.com!j35g2000prb.googlegroups.com!not-for-mail From: Jean-Paul Calderone Newsgroups: comp.lang.python Subject: Re: Why doesn't this asyncore.dispatcher.handle_read() get called? Date: Wed, 20 Apr 2011 13:01:08 -0700 (PDT) Organization: http://groups.google.com Lines: 116 Message-ID: <1ef2274c-7b8a-4e93-bbbc-d791df0e93da@j35g2000prb.googlegroups.com> References: <11c683ce-3687-4a07-9d59-0371ba84562e@e8g2000vbz.googlegroups.com> NNTP-Posting-Host: 66.31.201.117 Mime-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable X-Trace: posting.google.com 1303329669 32394 127.0.0.1 (20 Apr 2011 20:01:09 GMT) X-Complaints-To: groups-abuse@google.com NNTP-Posting-Date: Wed, 20 Apr 2011 20:01:09 +0000 (UTC) Complaints-To: groups-abuse@google.com Injection-Info: j35g2000prb.googlegroups.com; posting-host=66.31.201.117; posting-account=vglGDQoAAABmaDKgNY6lPt_hwJvC5hhE User-Agent: G2/1.0 X-HTTP-UserAgent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2.16) Gecko/20110319 Firefox/3.6.16,gzip(gfe) Xref: x330-a1.tempe.blueboxinc.net comp.lang.python:3744 On Apr 20, 12:25=A0pm, 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 =3D 9345 > > class Handler(asyncore.dispatcher): > =A0 =A0 def handle_read(self): > =A0 =A0 =A0 =A0 print 'This never prints' > > class Listener(asyncore.dispatcher): > =A0 =A0 def __init__(self, port=3DCOMM_PORT): > =A0 =A0 =A0 =A0 asyncore.dispatcher.__init__(self) > =A0 =A0 =A0 =A0 self.create_socket(socket.AF_INET, socket.SOCK_STREAM) > =A0 =A0 =A0 =A0 self.set_reuse_addr() > =A0 =A0 =A0 =A0 self.bind(('', port)) > =A0 =A0 =A0 =A0 self.listen(5) > > =A0 =A0 def handle_accept(self): > =A0 =A0 =A0 =A0 client, addr =3D self.accept() > =A0 =A0 =A0 =A0 print 'This prints.' > =A0 =A0 =A0 =A0 return Handler(client) > > class Sender(asyncore.dispatcher): > =A0 =A0 def __init__(self, host): > =A0 =A0 =A0 =A0 asyncore.dispatcher.__init__(self) > =A0 =A0 =A0 =A0 self.create_socket(socket.AF_INET, socket.SOCK_STREAM) > =A0 =A0 =A0 =A0 self.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1= ) > =A0 =A0 =A0 =A0 self.connect( (host, COMM_PORT) ) > =A0 =A0 =A0 =A0 self.buffer =3D 'Msg\r\n' > > =A0 =A0 def handle_connect(self): > =A0 =A0 =A0 =A0 pass > > =A0 =A0 def writable(self): > =A0 =A0 =A0 =A0 return len(self.buffer) > 0 > > =A0 =A0 def handle_write(self): > =A0 =A0 =A0 =A0 sent =3D self.send(self.buffer) > =A0 =A0 =A0 =A0 self.buffer =3D self.buffer[sent:] > > def test_communication(): > =A0 =A0 from multiprocessing import Process > =A0 =A0 def listener(): > =A0 =A0 =A0 =A0 l =3D Listener() > =A0 =A0 =A0 =A0 asyncore.loop(timeout=3D10, count=3D1) > =A0 =A0 lis =3D Process(target=3Dlistener) > =A0 =A0 lis.start() > =A0 =A0 def sender(): > =A0 =A0 =A0 =A0 s =3D Sender('localhost') > =A0 =A0 =A0 =A0 asyncore.loop(timeout=3D10, count=3D1) > =A0 =A0 sen =3D Process(target=3Dsender) > =A0 =A0 sen.start() > =A0 =A0 lis.join() > > test_communication() You didn't let the program run long enough for the later events to happen. loop(count=3D1) 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 =3D ServerFactory() factory.protocol =3D 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 =3D StringTransport() protocol =3D Handler() protocol.makeConnection(transport) protocol.dataReceived("X") self.assertEqual(transport.value(), "Y") Hope this helps, Jean-Paul