Part 2 shows this comment from the Linux TCP code:
/* As outlined in RFC 2525, section 2.17, we send a RST here because
* data was lost. To witness the awful effects of the old behavior of
* always doing a FIN, run an older 2.1.x kernel or 2.0.x, start a bulk
* GET in an FTP client, suspend the process, wait for the client to
* advertise a zero window, then kill -9 the FTP client, wheee...
* Note: timeout is always zero in such a case.
*/
Ok, so the RST is explained and well justified by the literature. But what are the “awful effects” of sending FIN instead? Can someone explain?
A few months ago I was debugging a similar issue in a Go-based service layer, where frequent HTTP requests to the same domain kept making fresh TCP connections when I was expecting TCP conn reuse.
In this situation we were discarding the HTTP response without reading it before closing, which kept Go from reusing the connection. I didn't dig quite as deep as this post's author, but I imagine the same RST behavior was happening under the hood.
The RST (Reset) is sent to inform the client that the data it sent was not read by the server. The RST avoids here the 4-way handshake for the TCP connection closure and the long wait times, if the client doesn't behave normal.
For the case here the server should call shutdown with SHUT_WR after sending the data and then drain the incoming data before closing the socket.
Really love this article. Opens with the problem statement and jumps straight into the investigation. Thanks for a very enjoyable read (and an rss feed!)
I remember seeing more or less the same bug 20 years ago... "Calling" process did connect, write, close. "Answering" process did accept, write("hello"), read, close. One of them got ECONNRESET on Windows NT, but not on some Unix variant (or possibly the other way around) because there was data (the "hello") that was sent but never read.
It it nice that there are some constants in this rapidly-changing world. =)
I encountered this few months back. Netcat was recv-only client connected to server that was continually sending some logs. Managed to trigger it with netcat killed with Ctrl+\ signal instead of Ctrl+C, but not consistently. My hypothesis was that it has something to do with unACKed data and/or non-empty incoming queue.
9 comments
[ 3.7 ms ] story [ 36.2 ms ] threadhttps://httpd.apache.org/docs/2.4/misc/perf-tuning.html
Um, yes? That's how TCP has been universally implemented for more than 30 years. See [0], 2.17 for discussion.
[0] https://www.rfc-editor.org/rfc/rfc2525#page-50
In this situation we were discarding the HTTP response without reading it before closing, which kept Go from reusing the connection. I didn't dig quite as deep as this post's author, but I imagine the same RST behavior was happening under the hood.
Here's a little reproducer: https://gist.github.com/jcalvinowens/da57edda9a01ca9f4c4088a...
...versus:For the case here the server should call shutdown with SHUT_WR after sending the data and then drain the incoming data before closing the socket.
It it nice that there are some constants in this rapidly-changing world. =)