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: RESOLVED NORESPONSE
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: 2018-03-13 11:07 UTC (History)
4 users (show)

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


Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.


Please create a new report on GitHub or Developer Community with your current version information, steps to reproduce, and relevant error messages or log files if you are hitting an issue that looks similar to this resolved bug and you do not yet see a matching new report.

Related Links:
Status:
RESOLVED NORESPONSE

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.
Comment 8 Marek Safar 2018-03-13 11:07:38 UTC
We have not received the requested information. If you are still experiencing this issue please provide all the requested information and reopen the bug report.

Thank you!