Documentation update
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
parent
32ed30d96b
commit
d7ea34ee71
21
docs/tcp.txt
21
docs/tcp.txt
@ -18,8 +18,11 @@ What will happen if we close the socket?
|
|||||||
received after close() is called, its TCP SHOULD send a RST
|
received after close() is called, its TCP SHOULD send a RST
|
||||||
to show that data was lost."
|
to show that data was lost."
|
||||||
|
|
||||||
IOW: if we just close(sock) now, kernel can reset the TCP connection,
|
IOW: if we just close(sock) now, kernel can reset the TCP connection
|
||||||
discarding some not-yet sent data.
|
(send RST packet).
|
||||||
|
|
||||||
|
This is problematic for two reasons: it discards some not-yet sent
|
||||||
|
data, and it may be reported as error, not EOF, on peer's side.
|
||||||
|
|
||||||
What can be done about it?
|
What can be done about it?
|
||||||
|
|
||||||
@ -46,14 +49,14 @@ This makes kernel send FIN after all data is written:
|
|||||||
|
|
||||||
However, experiments on Linux 3.9.4 show that kernel can return from
|
However, experiments on Linux 3.9.4 show that kernel can return from
|
||||||
shutdown() and from close() before all data is sent,
|
shutdown() and from close() before all data is sent,
|
||||||
and if peer sends any data to us after this, kernel stll responds with
|
and if peer sends any data to us after this, kernel still responds with
|
||||||
RST before all our data is sent.
|
RST before all our data is sent.
|
||||||
|
|
||||||
In practice the protocol in use often does not allow peer to send
|
In practice the protocol in use often does not allow peer to send
|
||||||
such data to us, in which case this solution is acceptable.
|
such data to us, in which case this solution is acceptable.
|
||||||
|
|
||||||
If you know that peer is going to close its end after it sees our FIN
|
Solution #3: if you know that peer is going to close its end after it sees
|
||||||
(as EOF), it might be a good idea to perform a read after shutdown().
|
our FIN (as EOF), it might be a good idea to perform a read after shutdown().
|
||||||
When read finishes with 0-sized result, we conclude that peer received all
|
When read finishes with 0-sized result, we conclude that peer received all
|
||||||
the data, saw EOF, and closed its end.
|
the data, saw EOF, and closed its end.
|
||||||
|
|
||||||
@ -61,6 +64,14 @@ However, this incurs small performance penalty (we run for a longer time)
|
|||||||
and requires safeguards (nonblocking reads, timeouts etc) against
|
and requires safeguards (nonblocking reads, timeouts etc) against
|
||||||
malicious peers which don't close the connection.
|
malicious peers which don't close the connection.
|
||||||
|
|
||||||
|
Solutions #1 and #2 can be combined:
|
||||||
|
|
||||||
|
/* ...set up struct linger... then: */
|
||||||
|
setsockopt(sock, SOL_SOCKET, SO_LINGER, &linger, sizeof(linger));
|
||||||
|
shutdown(sock, SHUT_WR);
|
||||||
|
/* At this point, kernel sent FIN packet, not RST, to the peer, */
|
||||||
|
/* even if there is buffered read data from the peer. */
|
||||||
|
close(sock);
|
||||||
|
|
||||||
Defeating Nagle.
|
Defeating Nagle.
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user