Bug 3844 - A blocking TCP socket send should block until all bytes are transmitted but can return early.
Summary: A blocking TCP socket send should block until all bytes are transmitted but c...
Status: NEEDINFO
Alias: None
Product: Class Libraries
Classification: Mono
Component: System (show other bugs)
Version: 2.10.x
Hardware: PC Linux
: --- normal
Target Milestone: Untriaged
Assignee: Bugzilla
URL:
Depends on:
Blocks:
 
Reported: 2012-03-10 21:23 UTC by Mike Chase
Modified: 2013-02-01 16:11 UTC (History)
4 users (show)

See Also:
Tags:
Is this bug a regression?: ---
Last known good build:


Attachments
Test that works the same on linux and windows (1.63 KB, text/plain)
2012-03-12 12:41 UTC, Gonzalo Paniagua Javier
Details

Description Mike Chase 2012-03-10 21:23:38 UTC
http://msdn.microsoft.com/en-us/library/w93yy28a%28v=vs.90%29.aspx#Y0

From the msdn documentation...

If you are using a connection-oriented protocol, Send will block until all of the bytes in the buffer are sent, unless a time-out was set by using Socket.SendTimeout. If the time-out value was exceeded, the Send call will throw a SocketException. In nonblocking mode, Send may complete successfully even if it sends less than the number of bytes in the buffer. It is your application's responsibility to keep track of the number of bytes sent and to retry the operation until the application sends the bytes in the buffer. There is also no guarantee that the data you send will appear on the network immediately. To increase network efficiency, the underlying system may delay transmission until a significant amount of outgoing data is collected. A successful completion of the Send method means that the underlying system has had room to buffer your data for a network send. 


In Mono this isnt the behaviour observed (2.10.5 Fedora 16).  I've had to use a construct like...

int amtSent = 0;

while (amtSent < _data.Length)
{
    amtSent += conn.Send(_data.data, amtSent, _data.Length - amtSent, socketFlags.None);
}

To get around the early termination.  The socket is in blocking mode and should block until all bytes are transmitted.
Comment 1 Gonzalo Paniagua Javier 2012-03-11 14:08:29 UTC
From your quote of the MSDN documentation: "Send may complete successfully
even if it sends less than the number of bytes in the buffer. It is your
application's responsibility to keep track of the number of bytes sent and to
retry the operation until the application sends the bytes in the buffer."
Comment 2 Mike Chase 2012-03-11 17:11:37 UTC
Read it closely.  The sentence you quote as well is referring to a non-blocking send which isn't the case with the error I am reporting.

The first section is the relevant one. I quoted the entire paragraph so it wasn't out of context... The section you referenced when closing this *is* out of context and only applies to a non-blocking send.

"If you are using a connection-oriented protocol, Send will block until all of
the bytes in the buffer are sent, unless a time-out was set by using
Socket.SendTimeout."

There was no timeout set and its a blocking send.  The bug report is valid and the current library behaviour is incorrect and breaks existing windows code.

Mike
Comment 3 Gonzalo Paniagua Javier 2012-03-12 12:07:46 UTC
The documented behavior with .NET (YMMV) is that the synchronous Send() might not send all the data BUT Begin/EndSend() guarantees that all the data will be sent.

The problem you are experiencing is due to different behavior of the TCP stack, including size of kernel buffers and such. Try your code on windows with a large buffer (2MB? 4MB?) and, if I recall correctly from testing this years ago, you will see how it won't send all the data.
Comment 4 Gonzalo Paniagua Javier 2012-03-12 12:33:48 UTC
MMm. Simple test blocks "forever" on Send() once the send buffer is filled up. Let me run my test on linux, may be on a Mac and then do the same thing but using Being/EndSend or SendAsync() and I'll report back.
Comment 5 Gonzalo Paniagua Javier 2012-03-12 12:41:34 UTC
Created attachment 1500 [details]
Test that works the same on linux and windows

The attached test behaves the same on windows and linux, i.e., it blocks once the send buffer is filled up. I don't see any partial reads or writes anywhere.

Could you provide a (similar) standalone test case that proves your point?

Thanks!
Comment 6 Mike Chase 2012-03-13 14:27:06 UTC
I'll need to work up a standalone test case.  One factor... This code was threaded.  A seperate reader and writer on the stream.  The sender was doing blocking writes.  

I'll get a test case together and post it as soon as possible.

Mike
Comment 7 Jeremiah Gowdy 2013-02-01 16:11:30 UTC
This bug is critical for our service when we run it on Mono.  Blocking sockets should not return from a send until the send is complete or failed, that is the behavior of non-blocking sockets.  Failure to honor this behavior results in BeginSend not being safe to call multiple times with preserved ordering, because the first BeginSend will "complete" with less than N bytes sent, after which the second queued BeginSend will be handled.  Standard behavior for BSD sockets on every platform I've written network code on is that send() will block until all the data has been sent in the default case of blocking sockets.

Note You need to log in before you can comment on or make changes to this bug.