<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>What's wrong with this code, part 5: The answers</title><link>http://blogs.msdn.com/larryosterman/archive/2004/08/05/209160.aspx</link><description>Yesterday&amp;rsquo;s post was a simple implementation of TransmitFile. First things first: I need to apologize. I was being a bit sneaky in this case. The code in the example was written to function correctly, and that mislead a lot of people who were trying</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>re: What's wrong with this code, part 5: The answers</title><link>http://blogs.msdn.com/larryosterman/archive/2004/08/05/209160.aspx#209278</link><pubDate>Thu, 05 Aug 2004 21:27:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:209278</guid><dc:creator>Keith Moore [exmsft]</dc:creator><description>FWIW: A couple of bits of socket trivia.&lt;br&gt;&lt;br&gt;1. The loop in TransmitTcpBuffer() is unnecessary if called with a stream-oriented socket (like, say, TCP). Calling WriteFile(), send(), or WSASend() on a stream-oriented socket will either a) completely send the entire buffer, or b) fail.&lt;br&gt;&lt;br&gt;2. Zero-byte sends may or may not actually cause packets to hit the wire, depending on the underlying protocol. For TCP, it's a noop. For UDP, it sends a zero-byte datagram. For message-oriented protocols (like SPX), it sends a zero-byte message.</description></item><item><title>re: What's wrong with this code, part 5: The answers</title><link>http://blogs.msdn.com/larryosterman/archive/2004/08/05/209160.aspx#209280</link><pubDate>Thu, 05 Aug 2004 21:30:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:209280</guid><dc:creator>Larry Osterman</dc:creator><description>Thanks Keith, trust the guy who wrote the code to know the REAL answer :)&lt;br&gt;  &lt;br&gt;Btw, the WriteFile()/send() behavior does NOT apply in general, even with Henry's TCP.&lt;br&gt;&lt;br&gt;For Exchange, we had issues with partial writes on Win16 and (I believe) Win9x, the RPC runtime didn't handle partial writes properly and that caused some &amp;quot;interesting&amp;quot; bugs.&lt;br&gt;</description></item><item><title>re: What's wrong with this code, part 5: The answers</title><link>http://blogs.msdn.com/larryosterman/archive/2004/08/05/209160.aspx#209328</link><pubDate>Thu, 05 Aug 2004 22:39:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:209328</guid><dc:creator>Anonymous</dc:creator><description>Thanks for your detailed answer. I have a question.&lt;br&gt;&lt;br&gt;Doesn't Windows have a per socket send/receive buffer?  Doesn't send() return after the data is stored in the buffer (instead of waiting for data to leave the wire).&lt;br&gt;&lt;br&gt;What about receive, when a TCP packet is received from the adapter doesn't it go to the receive buffer first?  How big is the buffer?  How can the size be changed?&lt;br&gt;&lt;br&gt;</description></item><item><title>re: What's wrong with this code, part 5: The answers</title><link>http://blogs.msdn.com/larryosterman/archive/2004/08/05/209160.aspx#209334</link><pubDate>Thu, 05 Aug 2004 22:46:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:209334</guid><dc:creator>Larry Osterman</dc:creator><description>Yes it has a per-socket send/receive buffer.&lt;br&gt;&lt;br&gt;But most networking APIs (and in this context writefile is a networking API) guarantee that the receiver has acknowledged receipt of the data before the write completes.  Otherwise you could lose data and not have any way of knowing it.&lt;br&gt;&lt;br&gt;There ARE varients that don't guarantee that data is received, but that's clearly spelled out in the API.&lt;br&gt;</description></item><item><title>re: What's wrong with this code, part 5: The answers</title><link>http://blogs.msdn.com/larryosterman/archive/2004/08/05/209160.aspx#209406</link><pubDate>Fri, 06 Aug 2004 00:48:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:209406</guid><dc:creator>Norman Diamond</dc:creator><description>8/5/2004 3:39 PM Anonymous&lt;br&gt;&lt;br&gt;&amp;gt; I have a question.&lt;br&gt;&lt;br&gt;Give or take an order of magnitude.&lt;br&gt;&lt;br&gt;&amp;gt; Doesn't send() return after the data is&lt;br&gt;&amp;gt; stored in the buffer&lt;br&gt;&lt;br&gt;Surely that part of it depends on the protocol and the socket options.&lt;br&gt;&lt;br&gt;8/5/2004 3:46 PM Larry Osterman&lt;br&gt;&lt;br&gt;&amp;gt; But most networking APIs [...] guarantee&lt;br&gt;&lt;br&gt;OK, UDP isn't &amp;quot;most&amp;quot;, but are the proportions really so unbalanced?  This makes me wonder if people who argued for putting acknowledgement in the original Ethernet design might have been right.</description></item><item><title>re: What's wrong with this code, part 5: The answers</title><link>http://blogs.msdn.com/larryosterman/archive/2004/08/05/209160.aspx#209408</link><pubDate>Fri, 06 Aug 2004 00:52:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:209408</guid><dc:creator>Larry Osterman</dc:creator><description>Norman, you're right.  I believe that you can configure sockets to return before the data is delivered, but that's NOT the default behavior.&lt;br&gt;&lt;br&gt;And yes, I think that the proportions are that unbalanced.  Networking is fundimentally an unreliable medium, but programmers want reliable transfer mechanisms.  So the networking guys designed their APIs to be as reliable as possible.  If you want unreliable, you need to ask for it.&lt;br&gt;</description></item><item><title>re: What's wrong with this code, part 5: The answers</title><link>http://blogs.msdn.com/larryosterman/archive/2004/08/05/209160.aspx#209413</link><pubDate>Fri, 06 Aug 2004 00:56:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:209413</guid><dc:creator>Larry Osterman</dc:creator><description>Norman, one example of a &amp;quot;you can shoot yourself in the foot if you want&amp;quot; is the Netbios sendnoack option - that would allow sends to complete before the receiver had completed them, but you had to handle the APIs specially (I don't remember the details now, it was about 15 years ago when I dealt with them).&lt;br&gt;</description></item><item><title>re: What's wrong with this code, part 5: The answers</title><link>http://blogs.msdn.com/larryosterman/archive/2004/08/05/209160.aspx#209625</link><pubDate>Fri, 06 Aug 2004 05:26:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:209625</guid><dc:creator>Random Reader</dc:creator><description>&amp;gt; I believe that you can configure sockets to return before the data is delivered, but that's NOT the default behavior.&lt;br&gt;&lt;br&gt;This doesn't make any sense.  There would be no point whatsoever to the socket's send buffer if this were the case.  A blocking send() would simply lock the application's buffer until done.  The docs imply that they don't work this way.&lt;br&gt;&lt;br&gt;Even send() explicitly states &amp;quot;The successful completion of a send does not indicate that the data was successfully delivered.&amp;quot; (&lt;a target="_new" href="http://msdn.microsoft.com/library/en-us/winsock/winsock/send_2.asp"&gt;http://msdn.microsoft.com/library/en-us/winsock/winsock/send_2.asp&lt;/a&gt;)&lt;br&gt;&lt;br&gt;WriteFile() shouldn't be special in this regard either, since you can't even guarantee it writes to a _file_ unless you disable all buffering on the handle, or flush it afterward.  Why would the network be special?</description></item><item><title>re: What's wrong with this code, part 5: The answers</title><link>http://blogs.msdn.com/larryosterman/archive/2004/08/05/209160.aspx#209652</link><pubDate>Fri, 06 Aug 2004 06:22:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:209652</guid><dc:creator>Random Reader</dc:creator><description>I followed this up with an extremely ugly and utterly non-robust test program:&lt;br&gt;&lt;br&gt;#include &amp;lt;stdio.h&amp;gt;&lt;br&gt;#include &amp;lt;winsock2.h&amp;gt;&lt;br&gt;#include &amp;lt;windows.h&amp;gt;&lt;br&gt;&lt;br&gt;int main(void)&lt;br&gt;{&lt;br&gt;	SOCKET s;&lt;br&gt;	WSADATA wsa;&lt;br&gt;	struct sockaddr_in sa = {0};&lt;br&gt;&lt;br&gt;	sa.sin_family = AF_INET;&lt;br&gt;	sa.sin_port = htons(9000);&lt;br&gt;	sa.sin_addr.S_un.S_addr = inet_addr(&amp;quot;192.168.0.6&amp;quot;);&lt;br&gt;&lt;br&gt;	WSAStartup(MAKEWORD(2,2), &amp;amp;wsa);&lt;br&gt;	s = socket(AF_INET, SOCK_STREAM, 0);&lt;br&gt;	connect(s, (struct sockaddr *)&amp;amp;sa, sizeof(sa));&lt;br&gt;	printf(&amp;quot;connect() finished\n&amp;quot;);&lt;br&gt;	getchar();&lt;br&gt;	send(s, &amp;quot;123&amp;quot;, 3, 0);&lt;br&gt;	printf(&amp;quot;send() finished\n&amp;quot;);&lt;br&gt;	getchar();&lt;br&gt;	closesocket(s);&lt;br&gt;	WSACleanup();&lt;br&gt;&lt;br&gt;	return 0;&lt;br&gt;}&lt;br&gt;&lt;br&gt;I used Sysinternals' TCPView to monitor things, since I obviously left error checking out of the code.  After the connection was made, I unplugged the target machine's network cable and tapped enter.  The send() completed immediately.&lt;br&gt;&lt;br&gt;What was fun to see was when I tapped enter again to close the socket and exit the program, and only then plugged the target back in.  Shortly afterward, it received the data :)&lt;br&gt;&lt;br&gt;What puzzles me at the moment is that I couldn't make WriteFile() work as a drop-in replacement for send() there.  It always reported ERROR_INVALID_PARAMETER, so I must be missing something.&lt;br&gt;&lt;br&gt;On a different note, why does a connected socket appear to hold the same local port open for listening as well?  For example, in one connection, local 192.168.0.5:6747 was ESTABLISHED to 192.168.0.6:9000, and local 0.0.0.0:6747 was LISTENING.  It's not possible to connect to, but I'm curious why it shows up at all.</description></item><item><title>re: What's wrong with this code, part 5: The answers</title><link>http://blogs.msdn.com/larryosterman/archive/2004/08/05/209160.aspx#209717</link><pubDate>Fri, 06 Aug 2004 09:10:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:209717</guid><dc:creator>StefanG</dc:creator><description>Sorry Larry, Your blog is usually quite excellent, but in this case there is definitely &lt;br&gt;something wrong with what you are saying.&lt;br&gt;&lt;br&gt;Assuming that no special socket options have been set, there are no serious perf problems with the code.&lt;br&gt;&lt;br&gt;Each socket by default has a kernel buffer of 8192 bytes. If the data you are writing in the WriteFile fits in the buffer&lt;br&gt;WriteFile returns immediately.&lt;br&gt;&lt;br&gt;The behaviour you describe will only happen if you have disabled the socket buffer by setting SO_SNDBUF to 0&lt;br&gt;&lt;br&gt;An article that describes these issues very well can be found at &lt;br&gt;&lt;a target="_new" href="http://support.microsoft.com/default.aspx?scid=kb;en-us;214397"&gt;http://support.microsoft.com/default.aspx?scid=kb;en-us;214397&lt;/a&gt;&lt;br&gt;&lt;br&gt;I have made some quick tests to verify what I am saying. I used pcattcp.exe which can be downloaded from&lt;br&gt;&lt;a target="_new" href="http://www.pcausa.com/Utilities/ttcpdown1.htm"&gt;http://www.pcausa.com/Utilities/ttcpdown1.htm&lt;/a&gt;&lt;br&gt;&lt;br&gt;Sending data in 4096-byte chunks with default options: 0.36 ms/call&lt;br&gt;SO_SNDBUF=0: 7.29 ms/call&lt;br&gt;SO_SNDBUF=0, TCP_NODELAY=1: 7.21 ms/call&lt;br&gt;&lt;br&gt;H:\ttcp&amp;gt;pcattcp -t -l 4096 srmutv&lt;br&gt;PCAUSA Test TCP Utility V2.01.01.07&lt;br&gt;TCP Transmit Test&lt;br&gt;  Remote Host : srmutv&lt;br&gt;  Transmit    : TCP -&amp;gt; 192.71.83.122:5001&lt;br&gt;  Buffer Size : 4096; Alignment: 16384/0&lt;br&gt;  TCP_NODELAY : DISABLED (0)&lt;br&gt;  Connect     : Connected to 192.71.83.122:5001&lt;br&gt;  Send Mode   : Send Pattern; Number of Buffers: 2048&lt;br&gt;  Statistics  : TCP -&amp;gt; 192.71.83.122:5001&lt;br&gt;8388608 bytes in 0.72 real seconds = 11362.00 KB/sec +++&lt;br&gt;numCalls: 2048; msec/call: 0.36; calls/sec: 2840.50&lt;br&gt;&lt;br&gt;H:\ttcp&amp;gt;pcattcp -t -l 4096 -b 0 srmutv&lt;br&gt;PCAUSA Test TCP Utility V2.01.01.07&lt;br&gt;TCP Transmit Test&lt;br&gt;  Remote Host : srmutv&lt;br&gt;  Transmit    : TCP -&amp;gt; 192.71.83.122:5001&lt;br&gt;  Buffer Size : 4096; Alignment: 16384/0&lt;br&gt;  SO_SNDBUF   : 0&lt;br&gt;  TCP_NODELAY : DISABLED (0)&lt;br&gt;  Connect     : Connected to 192.71.83.122:5001&lt;br&gt;  Send Mode   : Send Pattern; Number of Buffers: 2048&lt;br&gt;  Statistics  : TCP -&amp;gt; 192.71.83.122:5001&lt;br&gt;8388608 bytes in 14.57 real seconds = 562.21 KB/sec +++&lt;br&gt;numCalls: 2048; msec/call: 7.29; calls/sec: 140.55&lt;br&gt;&lt;br&gt;H:\ttcp&amp;gt;pcattcp -t -l 4096 -b 0 -D srmutv&lt;br&gt;PCAUSA Test TCP Utility V2.01.01.07&lt;br&gt;TCP Transmit Test&lt;br&gt;  Remote Host : srmutv&lt;br&gt;  Transmit    : TCP -&amp;gt; 192.71.83.122:5001&lt;br&gt;  Buffer Size : 4096; Alignment: 16384/0&lt;br&gt;  SO_SNDBUF   : 0&lt;br&gt;  TCP_NODELAY : ENABLED (1)&lt;br&gt;  Connect     : Connected to 192.71.83.122:5001&lt;br&gt;  Send Mode   : Send Pattern; Number of Buffers: 2048&lt;br&gt;  Statistics  : TCP -&amp;gt; 192.71.83.122:5001&lt;br&gt;8388608 bytes in 14.42 real seconds = 568.06 KB/sec +++&lt;br&gt;numCalls: 2048; msec/call: 7.21; calls/sec: 142.02&lt;br&gt;</description></item><item><title>re: What's wrong with this code, part 5: The answers</title><link>http://blogs.msdn.com/larryosterman/archive/2004/08/05/209160.aspx#209854</link><pubDate>Fri, 06 Aug 2004 14:31:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:209854</guid><dc:creator>Question</dc:creator><description>Wait a sec, is the Nagling algorithm turned on by default? If not, how do I turn it on for a socket? (I have an app that sends multiple small packets)&lt;br&gt;</description></item><item><title>re: What's wrong with this code, part 5: The answers</title><link>http://blogs.msdn.com/larryosterman/archive/2004/08/05/209160.aspx#209869</link><pubDate>Fri, 06 Aug 2004 15:01:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:209869</guid><dc:creator>Larry Osterman</dc:creator><description>I'm calling in the big guns for help (asked the winsock lead for comments).  He may comment later.  But here's my comments off the top of my head.&lt;br&gt;&lt;br&gt;Question: As far as I know, nagling is ON by default.  The easy way to tell is to run Stephan's test with 10 byte writes and look at the results from a remote machine - if the data is transmitted on the wire immediately in 10 byte writes nagling's disabled.  If it's transmitted in larger writes it's enabled.&lt;br&gt;&lt;br&gt;Stephan, did you try the same test with an odd number of frames with a buffer GREATER than 8192 bytes that takes an odd number of frames?  Also, to see this behavior you need TWO machines - one transmits the data, the other measures the throughput.  Having netmon (or etherial) capture the data would also show the behavior.&lt;br&gt;&lt;br&gt;It's possible that http.sys sets SO_SNDBUF to 0, which is why we didn't see this in WMC earlier this week.&lt;br&gt;&lt;br&gt;But the behavior is VERY real, and it's burned more people than I can think of.&lt;br&gt;</description></item><item><title>re: What's wrong with this code, part 5: The answers</title><link>http://blogs.msdn.com/larryosterman/archive/2004/08/05/209160.aspx#209961</link><pubDate>Fri, 06 Aug 2004 16:48:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:209961</guid><dc:creator>Anonymous</dc:creator><description>Assuming Larry is right, and assuming default send buffers, isn't it difficult to make sure the sent data is acknowledged.  Say one thread sends 100 byes using WriteFile() and waits for ack, and another thread sends 200 bytes on the same socket.  Now on a stream protocol like TCP, the driver has to mark the boundary after the first send and monitor it, and it is painful to implement that feature.  This gets complicated with overlapped I/O.&lt;br&gt;&lt;br&gt;Coming from the unix world, I think the only way to guarantee data delivery is to set the send buf to 0 bytes, even that probably only waits for data to leave the wire, doesn't wait for the ack (I am not sure though).&lt;br&gt;&lt;br&gt;This an interesting discussion, Thanks StefanG and Random Reader for your thougts.</description></item><item><title>re: What's wrong with this code, part 5: The answers</title><link>http://blogs.msdn.com/larryosterman/archive/2004/08/05/209160.aspx#209965</link><pubDate>Fri, 06 Aug 2004 17:00:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:209965</guid><dc:creator>Larry Osterman</dc:creator><description>From the winsock wizards, when I asked them:&lt;br&gt;Yes, Winsock has implemented this default 8k buffer exactly for this reason - make such naive apps work.  After all most of the apps out there send relatively small packets and cost of extra copy is cheaper that locking the buffer and sending directly from application space.  And for those that need to send files, there is a TransmitFile API that implements proper dual buffer technique.&lt;br&gt;&lt;br&gt;So my app would be broken given a larger buffer size.  I'm still trying to get confirmation that http.sys sets SO_SNDBUF to 0, which would complete my understanding of why I messed up so badly.&lt;br&gt;&lt;br&gt;As I said: This IS a real problem, and it shows up with great regularity, which is why I wanted to write about it.  It was my mistake in not actually verifying this with a real application :(&lt;br&gt;&lt;br&gt;</description></item><item><title>The consequences of ignoring nagling and delayed acks</title><link>http://blogs.msdn.com/larryosterman/archive/2004/08/05/209160.aspx#210041</link><pubDate>Fri, 06 Aug 2004 21:33:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:210041</guid><dc:creator>Larry Osterman's WebLog</dc:creator><description /></item><item><title>re: What's wrong with this code, part 5: The answers</title><link>http://blogs.msdn.com/larryosterman/archive/2004/08/05/209160.aspx#210076</link><pubDate>Fri, 06 Aug 2004 19:05:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:210076</guid><dc:creator>Simon Cooke [exMSFT]</dc:creator><description>Anon: I set the buffer to 0 on the high-throughput networking stuff I'm doing. Couple it with overlapped io and it allows one to at least get a certain amount of control over network throttling.</description></item><item><title>re: What's wrong with this code, part 5: The answers</title><link>http://blogs.msdn.com/larryosterman/archive/2004/08/05/209160.aspx#210478</link><pubDate>Sat, 07 Aug 2004 09:15:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:210478</guid><dc:creator>Random Reader</dc:creator><description>Ahh, that explains it.&lt;br&gt;&lt;br&gt;And to follow up on my WriteFile() trouble, it turns out that socket() always creates an overlapped socket, and WriteFile() requires a valid OVERLAPPED structure to work on such handles.  The fix was to simply use WSASocket() with no flags.&lt;br&gt;&lt;br&gt;Despite any mistakes, it's good to get all this stuff cleared up.</description></item><item><title>re: What's wrong with this code, part 5: The answers</title><link>http://blogs.msdn.com/larryosterman/archive/2004/08/05/209160.aspx#211050</link><pubDate>Mon, 09 Aug 2004 03:26:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:211050</guid><dc:creator>pUnk</dc:creator><description>1568? Regular old Ethernet is 1518 from Ethernet header to/including FCS.</description></item><item><title>re: What's wrong with this code, part 5: The answers</title><link>http://blogs.msdn.com/larryosterman/archive/2004/08/05/209160.aspx#211325</link><pubDate>Mon, 09 Aug 2004 16:19:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:211325</guid><dc:creator>Larry Osterman</dc:creator><description>pUnk,  I could have sworn that 1568 was max ethernet frame size, but clearly that's not right.&lt;br&gt;</description></item></channel></rss>