As per title. Sorry if this is a duplicate question, but in the numerous posts online, I could only find how a connection is torn down, but not (convincingly) why it is done in such a way.
1. A -----FIN-----> B
2. A <----ACK------ B
3. A <----FIN------ B
4. A -----ACK-----> B <====== Why is this one necessary?
======if 3 or 4 lost=======
5. A <....FIN...... B
6. A .....ACK.....> B
It seems B can shutdown the socket as soon as it sends out its FIN(3)
because
- if the
FIN(3)
is not lost, all is well. - if it is lost, A can timeout anyway and close the connection. One can argue that if this does happen, A will have to wait for a very long time. But B bears some risk with this last
ACK(4)
as well. Suppose the connection suddenly goes down (though with low probability) right after A sends out the lastACK(4)
, causing B unable to receive it. Then B will have to wait and timeout, too. Since both approaches are flawed, why not save this lastACK
?
My guess
I think the only exception is that there is a reasonably high chance of packet loss such that both FIN(3)
and ACK(4)
won't arrive.
If FIN(3)
is lost, receiving nothing back from A, B will resend its new FIN(5)
.
Similarly, if ACK(4)
is lost, B will think that its FIN(3)
is lost and resend the FIN(5)
as well. A, though having sent out ACK(4)
, is supposed in the TIME-WAIT
status, will hopefully receive this new FIN(5)
and resend an ACK(6)
.
It seems only if the scenario described above happens reasonably frequently, will the last ACK(4)
have a significant impact.
Best Answer
The ACK to a FIN is required because the end sending the FIN will retransmit it until it receives an ACK. So, the question is, why TCP keeps sending the FIN if not ACK is received? My understanding is that given that a connection may be in a half-close state, the side that is receiving the last FIN (A in your diagram) may be waiting for data "indefinitely" wasting resources in that end when no more data will be received. B needs to be sure that A received the FIN (and closes the connection), hence it requires an ACK.
Edit
To be more precise about half-close. In your example, A can close its side of the connection sending the first FIN and receiving the first ACK, but B can keep sending more data at will for any period of time before closing the connection and sending the last FIN. So, the time between the first FIN/ACK sequence and the second one can't be determined or timed-out. A needs the last FIN to be sure B has closed its side of the connection.
Edit 2
What happen if the last FIN from B to A is lost? Then, B will not receive the ACK and will retransmit the FIN until it receives an ACK. So, A will eventually get the FIN and transition to the TIME_WAIT state.
What happen if the last ACK is lost? Then, B will think that A did not receive the FIN and will retransmit the FIN. From B point of view this is the same as if the FIN was lost, from A point of view this different since A now is in the TIME_WAIT or CLOSED state. When A receives the new FIN from A if it is in the TIME_WAIT state it will send the ACK again.
If A is in the CLOSED state it will send a RESET, in either case B will be able to close its side of the connection.