Tcp – Why is the last ACK needed in TCP four way termination

layer4tcp

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

  1. if the FIN(3) is not lost, all is well.
  2. 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 last ACK(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 last ACK?

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

A -----FIN-----> B
FIN_WAIT_1       CLOSE_WAIT
A <----ACK------ B
FIN_WAIT_2

(B can send more data here, this is half-close state)

A <----FIN------ B
TIME_WAIT        LAST_ACK
A -----ACK-----> B
|                CLOSED
2MSL Timer
|
CLOSED

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.

A -----FIN-----> B
FIN_WAIT_1       CLOSE_WAIT
A <----ACK------ B
FIN_WAIT_2

(B can send more data here, this is half-close state)

A  (Lost)X<--FIN------ B
FIN_WAIT_2       LAST_ACK
                 (timeout waiting for ACK)
A <----FIN------ B
TIME_WAIT
A -----ACK-----> B
|                CLOSED
2MSL Timer
|
CLOSED

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.

A -----FIN-----> B
FIN_WAIT_1       CLOSE_WAIT
A <----ACK------ B
FIN_WAIT_2

(B can send more data here, this is half-close state)

A <----FIN------ B
TIME_WAIT        LAST_ACK
A -----ACK-->X(Lost)   B
TIME_WAIT        LAST_ACK
                 (timeout waiting for ACK)
A <----FIN------ B
A -----ACK-----> B
|                CLOSED
2MSL Timer
|
CLOSED

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.

A -----FIN-----> B
FIN_WAIT_1       CLOSE_WAIT
A <----ACK------ B
FIN_WAIT_2

(B can send more data here, this is half-close state)

A <----FIN------ B
TIME_WAIT        LAST_ACK
A -----ACK-->X(Lost)   B
TIME_WAIT        LAST_ACK
|
2MSL Timer
|
CLOSED
                 (timeout waiting for ACK)
A <----FIN------ B
A -----RST-----> B
                 CLOSED