[Twisted-Python] protocol and transport question
Jean-Paul Calderone
exarkun at divmod.com
Tue Aug 21 06:02:27 MDT 2007
On Tue, 21 Aug 2007 13:02:34 +0200, Luca Politti <luca at unipex.it> wrote:
>Hi all,
>I have a problem with a simple client/server communication: I have a
>server that send the data through "transport" (my class inherit from
>twisted.internet.protocol.Protocol), every 0.4 seconds. On the client
>(that now, for test propose are on the same machine) some time I receive
>two messages concatenated from the server like it send on the same time.
>Other times, I receive it correctly (in different moments).
For message-oriented protocols (what you seem to be implementing), it
is necessary to have some "framing" mechanism - a way to tell where a
message ends and the next begins. You can't rely on time to tell
messages apart over TCP, since TCP makes few guarantees about when it
will do things.
>I tried to debug this situations with print some messages, and I see
>that twisted sometimes wait "a time" before send data through the
>channel:
Bytes written to a TCP transport will be sent (almost) as soon as they
can be. They are not (in the current implementation) sent before the
transport.write() call returns, but they will be sent the next time the
reactor regains execution control. Unless your application is blocking
the reactor from running (ie, performing some long running task), this
means the reactor will try to send your data at most a few milliseconds
after your write call. It is not necessarily the case that the send will
succeed at that time, though. In such a case, the reactor will buffer
the data and try to send it again later.
>
>on the server, on twisted.internet.tcp.Connection on writeSomeData I add:
>print "CCCCCCCCCCCCCCCCC", repr(data), time.time()
>try:
> # Limit length of buffer to try to send, because some OSes are too
>....
>
>on my code:
>print "BBBBBBBBBBBBBBBBBBB", repr(msg), time.time()
>self.transport.write(str(msg))
writeSomeData and transport.write don't necessarily have a one-to-one
correspondence to each other, so this debug output might be a bit
misleading.
> [snip]
>
>How solve it? Is there a method for say to twisted (transport) to not
>wait to send the data? (flush the buffer?)
Since there's no buffering except when absolutely necessary, there's no
way to flush.
So there are three things to watch out for:
* You must use a framing mechanism in order to differentiate your
messages. This might be as simple as having them all be the same
length, or it might mean including a length prefix (see the
NetstringReceiver or Int{8,16,32}StringReceiver protocols in
twisted.protocols.base for examples of this), or it might be
something more complex.
* Don't block the reactor. If you want to wait a while, use the
callLater method of the reactor, not time.sleep. If you have
to call a function that will block for a long time before it
returns, find an asynchronous version instead, or use the reactor's
threadpool.
* Don't call reactor methods from any thread except the one which
is running the reactor. This will have unpredictable results and
generally be broken.
Jean-Paul
More information about the Twisted-Python
mailing list