5

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.

7
  • Did any answer help you? if so, you should accept the answer so that the question doesn't keep popping up forever, looking for an answer. Alternatively, you could post and accept your own answer.
    – Ron Maupin
    Jan 6, 2021 at 0:00
  • @RonMaupin The answers so far are helpful, but did not address the question directly.
    – wlnirvana
    Jan 7, 2021 at 5:11
  • 1
    Ok. We are working on the year-end cleanup to see how many open questions with answers we can get completed. If you get an answer, you can answer yourself and accept it. The question of why the last ACK is required is just that nay FIN only means that the sender of the FIN is done sending, and it must still be open to receive more segments, and it must resend any unacknowledged segments. Each side is a peer (client/server is an application concept), and both sides must agree that everything is done.
    – Ron Maupin
    Jan 7, 2021 at 5:25
  • In my diagram, A already sent a FIN and received the ACK from B, so I suppose B does not need to remain open for more data.But the "resend any unacknowledged segments" argument is inspiring. Suppose B has 3 packets to send. Is B allowed to send its own FIN before receiving A's ACK for packet 3?
    – wlnirvana
    Jan 7, 2021 at 5:41
  • "Suppose B has 3 packets to send. Is B allowed to send its own FIN before receiving A's ACK for packet 3?" B will not send a FIN until it is done sending everything it has to send. One side cannot force the other the end. If one side sends FIN, it can only resend segments (not packets) and ACKs to acknowledge any segments it receives from the side not finished sending. Each side must acknowledge it understands the other side is done sending when it has received a FIN. Remember, they are peers.
    – Ron Maupin
    Jan 7, 2021 at 5:48

3 Answers 3

9
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
10
  • Thanks for the answer.Your reasoning is that B has to know A has received FIN(3) so that A will close its connection. But following this same reasoning, to guarantee that B will close its connection as well, A had better get an extra ACK from B to know B indeeds receives A's ACK(4). And this falls back to the two-armies problem mentioned by @JeanPierre. However this extra ACK is not required by the TCP protocol. But why is this the case?
    – wlnirvana
    Feb 13, 2017 at 2:52
  • @wlnirvana Please see my update. Let me know if that clarifies your doubts. Feb 13, 2017 at 14:41
  • Thank you very much for the detailed explanation. For the mechanism you illustrated to work significantly better than my proposal (getting rid of the last ACK), I guess the packet loss rate should not be very low?
    – wlnirvana
    Feb 14, 2017 at 4:10
  • 1
    i don't see how you can get rid of the last ACK. Please, recall that A can't timeout waiting for a FIN and B should receive the ACK to stop resending the FIN. Feb 14, 2017 at 13:40
  • Why "A can't timeout waiting for a FIN"? What if the physical cable is unplugged? Will A wait infinitely?
    – wlnirvana
    Feb 16, 2017 at 5:41
1

There are 2 pairs of FIN/ACKs because in TCP each direction of the stream is closed separately. When A sends a FIN to B, it means that A will not send any more data to B. The connection can remain open and B can send as many data as it wants. Once B sends the second FIN, the data stream is closed in both directions and connection can be terminated.

One example where this could be useful is HTTP (actually was HTTP a long time ago, with modern web-pages its more complicated). A client sends the server HTTP request containing requested URL. Then the client can send the FIN. The server knows that it will not receive any data from the client and clear TCP buffer / potentially some other connection state. The server then sends the web-page over this connection.

To deal with lost FINs and corresponding ACKs, TCP is required to keep some of the connection state for some predefined time after both FINs are sent (i think it is about 2min, but it should be in TCP standard). In particular, if the sender of the FIN does not receive an ACK, it re-transmits the FIN.

I think i saw a function in Linux socket API that only closes outgoing stream, i.e., you can still read from the socket but can't write to it. I can't remember what it is called :(

0

TCP provides a reliable transmission service. This includes each party knowing it has received all the data the other intended to transmit. In your example, A won't know it has received all B's data until it receives the FIN. B is going to retransmit the FIN, so that it knows that A knows all data has been transmitted.

As a side note, this also implies A needs to "stay here" after it has sent its ACK to B's FIN: when B retransmits the FIN, if A's gone, B won't get any ACK (and possibly a RST) and so cannot guarantee A knows it has received all data. A stays some time in the TIME_WAIT state to ACK such retransmitted FINs. Strictly, it would need to stay there until it knows B has received its ACK but that's an unsolvable problem often dubbed the "two-armies" problem.

5
  • I understand what you said and how TCP is designed, but my question is why it is designed as it is. As the two-armies problem you mentioned, it is theoretically unsolvable, thus impossible to be 100% reliable. For example if the network fails in step 4, right after A sends the ACK and before B receives it, B will end up retrying the FIN infinitely. So why the ACK?
    – wlnirvana
    Feb 13, 2017 at 2:38
  • @wlnirvana It will not retry infinitely but will give up at some point (this is true for all the segments to be ack'ed not just the FINs). In this case, B can't be sure the transfer was successfull. When the network fails no reliable tranfer can be performed, but if it does not then: 1. receiving the FIN, A knows it has received all data so the transfer is successfull; 2. receiving the ACK, B knows A knows it has received all data, so it also know the transfer is successfull. If one of these two segments are lost they will be retransmitted.
    – JeanPierre
    Feb 14, 2017 at 10:00
  • But even without "1. receiving the FIN" (i.e. the FIN is lost and B has closed the connection on its side), A still knows that the data previously transmitted were successful. Though A is not sure if more data will come, it can wait up to a certain amount of time and then close its connection.
    – wlnirvana
    Feb 16, 2017 at 5:48
  • Imagine the message sent by B is Transfer the following amount to Mr X: $ 10000 but A receives Transfer the following amount to Mr X: $ 10. A wants to know it has received the whole message.
    – JeanPierre
    Feb 16, 2017 at 9:52
  • Where does this message Transfer ... come from? It seems you are suggesting the case where the FIN packet itself carries data. While this is possible with TCP, we can easily design another protocol (let's call it TNTCP for TNTCP is Not TCP) that forbids FIN+data. In other words, if B wants to say the message Transfer ..., B must send it and receive the ACK before B sends out a "clean" FIN. And with TNTCP, B closes its connection as soon as the FIN is sent out. In this case do we still need the last ACK?
    – wlnirvana
    Feb 16, 2017 at 10:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.