Questions about asyncore

Giampaolo Rodola' gnewsg at gmail.com
Tue Jul 29 09:40:10 EDT 2008


On 29 Lug, 13:09, Frank Millman <fr... at chagford.com> wrote:

> Firstly, having got asyncore working, I had a look at asynchat. As far
> as I can see I get very little benefit from using it. I have already
> set up a 'messaging' protocol between server and client, where all
> messages consist of 5 digits for the message length, followed by the
> message. The message consists of a pickled tuple, where the first
> element is a message identifier, and the rest is the message body.
>
> This is how it works in asyncore -
>
>     def __init__(self,channel):
>         [...]
>         self.msgLength = 0
>         self.recvData = ''  # temporary buffer
>
>     def handle_read(self):
>         self.recvData += self.recv(8192)
>         if not self.msgLength:
>             if len(self.recvData) < 5:  # 1st 5 bytes = msg length
>                 return
>             self.msgLength = int(self.recvData[:5])
>             self.recvData = self.recvData[5:]
>         if len(self.recvData) < self.msgLength:
>             return
>         data = loads(self.recvData[:self.msgLength])
>         self.recvData = self.recvData[self.msgLength:]
>         self.msgLength = 0
>         [handle data]
>
> This is how I got it working in asynchat -
>
>     def __init__(self,channel):
>         [...]
>         self.recvData = ''  # temporary buffer
>         self.set_terminator(5)
>         self.gotMsgLength = False
>
>     def collect_incoming_data(self, data):
>         self.recvData += data
>
>     def found_terminator(self):
>         if self.gotMsgLength:  # what follows is the message
>             data = loads(self.recvData)
>             self.set_terminator(5)
>             self.gotMsgLength = False
>             [handle data]
>         else:  # what follows is the message length
>             self.set_terminator(int(self.recvData))
>             self.gotMsgLength = True
>         self.recvData = ''
>
> It may be slightly neater, but it does not seem worth adding an extra
> layer just for that. Does asynchat give me any other benefits I may
> have overlooked?

The benefit of asynchat is that it automatically handles the buffering
of both input and output.
Aside from set/found_terminator() the other two methods you could want
to look at are push() and push_with_producer().
push() is a buffered version of asyncore.send(), push_with_producer()
accepts a data-producer object you can use in case you want to deal
with something other than strings (e.g. files, lists, generators, and
so on...).


> My second question relates to writing a dummy client program to test
> the server. I just want to send it some messages and print the
> responses. Some messages incorporate data extracted from previous
> responses, so I have to wait for the reply before continuing.
>
> I am using asyncore for this as well. However, the only way I can
> think of to get it working is to run asyncore.dispatcher in a separate
> thread.
>
> To send messages, I append them to a list of messages to be sent. The
> dispatcher method writable() returns True if there is anything in the
> list, else False.
>
> To receive messages, I run a 'while 1' loop in the main thread, with a
> sleep of 0.1, until recvData has something in it.
>
> It works, but it seems odd to use a separate thread, as one of the
> points of asyncore is to avoid multi-threading. Is there a better way
> to write the client program?

I'm not sure to understand but I doubt you have to use a thread.
If you "have to wait for the reply before continuing" just implement
this logic into handle_read() or found_terminator() method.


--- Giampaolo
http://code.google.com/p/pyftpdlib/



More information about the Python-list mailing list