问题
I was reading about using the SO_LINGER socket option to intentionally 'assassinate' the time-wait state by setting the linger time to zero. The author of the book then goes on to say we should never do this and in general that we should never interfere with the time-wait state. He then immediately recommends using the SO_REUSEADDR option to bypass the time-wait state.
My question is, what's the difference? In both cases you're prematurely terminating the time-wait state and taking the risk of receiving duplicate segments. Why is one good and the other bad?
回答1:
TIME_WAIT is absolutely normal. It occurs after a TCP FIN on the local side followed by a TCP FIN ACK from the remote location. In TIME_WAIT you are just waiting for any stray packets to arrive at the local address. However if there is a lost or stray packet then TIME_WAIT ensure that TTL or "time to live" expires before using the address again.
If you use SO_REUSEADDR then you are basically saying, I will assume that there are no stray packets. Which is increasingly likely with modern, reliable, TCP networks. Although it is still possible it is unlikely.
Setting SO_LINGER to zero causes you to initiate an abnormal close, also called "slamming the connection shut." Here you do not respect TIME_WAIT and ignore the possiblity of a stray packet.
If you see FIN_WAIT_1 then this can cause problems, as the remote location has not sent a TCP FIN ACK in response to your FIN. So the process was either killed or the TCP FIN ACK was lost due to a network partition or a bad route.
When you see CLOSE_WAIT you have a problem, here you are leaking connections as you are not sending the TCP FIN ACK when given the TCP FIN.
回答2:
I did some more reading and this is my understanding of what happens (hopefully correct):
When you call close on a socket which has SO_REUSEADDR set ( or your app crashes ) the following sequence occurs:
- TCP Sends any remaining data in the send buffer and a FIN
- If close was called it returns immediately without indicated if any remaining data was delivered successfully.
- If data was sent the peer sends a data ACK
- The peer sends an ACK of the FIN and sends it's own FIN packet
- The peer's FIN is acked and the socket resources are deallocated.
- The socket does not enter TIME-WAIT.
When you close a socket with the SO_LINGER time set to zero:
- TCP discards any data in the send buffer
- TCP sends a RST packet to the peer
- The socket resource are deallocated.
- The socket does not enter TIME-WAIT
So beyond the fact that setting linger to zero is a hack and bad style it's also bad manners as it doesn't go through a clean shutdown of the connection.
回答3:
I have use SO_REUSEADDR to wildcard bind() to a local port for which some other program already had a connection open on. It turns out this particular use will never cause a problem so long as no two sockets try to listen() on the same addr/port combo at the same time.
来源:https://stackoverflow.com/questions/587961/whats-the-difference-between-time-wait-assassination-and-so-reuseaddr