Archived

This topic is now archived and is closed to further replies.

Zipster

Asynchronous data transfer

Recommended Posts

I'm writing a Windows Forms application in C# that needs to use asynchronous network operations to keep the user interface responsive while large amount of data are streamed. I'm using TcpClient in conjunction with NetworkStream and had a few lingering questions that MSDN didn't seem to fully address. 1) When I begin an asynchronous send with NetworkStream.BeginWrite(...) while the recipient has started an asynchronous read (NetworkStream.BeginRead(...)), is there any guarantee that NetworkStream.DataAvailable will be non-zero as long as the asynchronous send hasn't completed? In other words, does the recipient client understand that the send is asynchronous, or is there a chance that during the transfer that DataAvailable will be zero temporarily? The reason I ask is because if I set up a loop in my asynchronous read callback that depends on DataAvailable to be non-zero until all of the data is sent, then if it happens to be zero prematurely it might break the loop before all the data is received. My alternative would be to create a custom escape message that specifically tells the client a data transfer is complete, and not rely on DataAvailable at all, but I was wondering if there are already provisions in place for this kind of scenario. 2) What are the implications of setting TcpClient.NoDelay to true? I understand that it tells the client to send data before the send buffer is completely full, but do I risk sending a lot of small packets? The reason I ask, is because during the connection phase of two clients a lot of small handshake messages (mostly swapping encryption keys) are sent back and forth, and when I was using raw sockets before sometimes I found that the messages weren't being sent, since NoDelay was false and the buffer wasn't filled yet. One option I have is to set NoDelay to true for the initial phase of small packet transfer, then set it to false again when I'm streaming the large amounts of data. Thanks for your time. I know that was all a mouthful [edited by - Zipster on May 26, 2004 6:59:34 PM]

Share this post


Link to post
Share on other sites
I woke up this morning with a few more questions on my mind, so please bear with me

3) If I were to keep NoDelay to true when sending large amounts of data, will the network layer send a packet before the buffer is full, even if there is sufficient data to fill the buffer? Can the OS act efficiently in this respect even with NoDelay set, or does that completely disable the logic?

And one last thing I was considering... since my application will have to be in a constant state of listening for connections, as well as for receiving incoming data, does that mean I always have to have an asynchronous read operation going on in the background? Otherwise, my application won''t know when data has arrived. My other alternative is to create a separate thread that just sits around, checking DataAvailable, and reading in whatever it gets. In that case, I''ll most definitely need a custom escape message since my read operations will operate continuously. I''ve heard of using IOCP, and I even followed a tutorial a few weeks ago on writing an IOCP-backed thread pool for generic data processing. Would that help me out here?

This is really my first foray into network programming, so forgive me if I''m overlooking any basic design

Share this post


Link to post
Share on other sites
The nodelay flag is an implementation hint that the use of the protocol is interactive, and thus the implementation should send available TCP data in an IP packet, if there is still available window space, at the end of each system call that hands data to the implementation.

This means that write("foo",3); write("bar",3); might send two packets with TCP_NODELAY set, and one packet otherwise (although nothing is guaranteed; these are implementation hints only). Typically, if NODELAY isn''t set, the implementation may wait for some time specific to the implementation after receiving data from the user, before sending it on the network.

It would be a correctness problem if a TCP implementation NEVER sent the data unless it filled a buffer. That''s not allowed in the protocol spec. (Or at least highly non-useful; the protocol doesn''t really specify the implementation API :-)

If you write a large chunk of data in one go, the sending of that data will usually be efficient no matter whether NODELAY is set or not.

Share this post


Link to post
Share on other sites
Great, thanks for the reply. Just for reference, what timescale are we talking about when mentioning how long the protocol waits before sending a partially filled buffer? A few milliseconds? A few seconds? (God forbid) 30/60 seconds? Is there any change in behavior from synchronous to asynchronous communication? Also, what are some common scenarios in which NoDelay would be set/unset?

Sorry to bombard you with all these questions

Share this post


Link to post
Share on other sites
The implementation defines how long it is. I think the value has traditionally been 200 milliseconds on BSD based kernels, but I could be wrong.

The underlying network stack does not know whether you use synchronous or asynchronous I/O to exchange data with it, so it shouldn''t matter.

NODELAY will typically be set for interactive sessions (such as a "telnet" or "ssh" session to a UNIX command line prompt) and not set for batch/transaction sessions, such as HTTP responses or file transfers. A browser that wants high performance might turn on NODELAY and make sure it forms the entire request into a single write(), to get a faster turn-around time; again it''s the interactivity that steers this.

Share this post


Link to post
Share on other sites