Location>code7788 >text

Difference between socket close and shutdown, TIME_WAIT and CLOSE_WAIT

Popularity:565 ℃/2024-09-21 12:39:25

TCP active connection closure
 
appl: close(), --> FIN FIN_WAIT_1 //Actively close the socket party, call close to close the socket, issue FIN
<-- ACK FIN_WAIT_2 // The TCP layer of the other OS, gives the ACK response. Then give FIN
               <-- FIN
--> ACK "TIME_WAIT" -- 2MSL timeout --> CLOSED //TIME_WAIT, to prevent ACK from not being given to the other side.
 
TCP passive connection closure
 
<-- FIN "CLOSE_WAIT" // Passive party, received FIN from other party, in CLOSE_WAIT state
--> ACK // TCP layer on passive side, give ACK response
app2: close(), --> FIN LAST_ACK //passive party calls close to go from CLOSE_WAIT to LAST_ACK Without calling close, it will stay in CLOSE_WAIT state.
<-- ACK --> CLOSED tcp is full duplex :: so close() shuts down reads and writes. shutdown() optionally shuts down reads or writes. The time_wait can be very long, so server minimizes actively closing connections.
 
 
int close(int sockfd); int shutdown(int sockfd, int howto); // howto: SHUT_RD, SHUT_WR, SHUT_RDWR
The shutdown() function serves two purposes:
close() decrements the reference count of the description word by one and closes the socket only when the reference count is zero.
For example, in fork() mode, after the parent process returns from accept(), fork() the child process, which will handle connfd, and the parent process will close(connfd); but at this time, the parent's close() does not raise a FIN.
 

shutdown(), on the other hand, does not care about the socket's reference count and a FIN occurs directly.
shutdown() controls the pipeline in both read/write directions.
SHUT_RD shutdown(sockfd, SHUT_RD); After this, all data from the opposite end is acknowledged and then quietly discarded. SHUT_WR half close state.
 
4 interactions triggered by close(): (here close is initiated by client)
 
client server
FIN_WAIT_1 ---- FIN M ------> (TCP layer response ACK packet from OS on Server side)
<---- ACK M+1---- CLOSE_WAIT FIN_WAIT_2 (close must be called here to go from CLOSE_WAIT to LAST_ACK)
<------ FIN N ----- LAST_ACK TIME_WAIT (TIME_WAIT has an important role in preventing the loss of the last ACK)
------- ACK N+1 ----------> CLOSE
TIME_WAIT is formed when the link is actively closed, waiting for 2MSL time, about 4 minutes.

The main reason is to prevent the loss of the last ACK. Since time_wait can be very long, the server side should minimize actively closing the connection

 

CLOSE_WAIT is a passive close link is formed , the

According to the state machine, when our side receives a FIN, the TCP implementation sends an ACK and therefore enters the CLOSE_WAIT state.

However, if we do not execute close(), we cannot migrate from CLOSE_WAIT to LAST_ACK, and there will be a lot of connections with CLOSE_WAIT status in the system.

At this time, the system may be busy processing read and write operations, but not the connection has received FIN, for close. at this time, recv/read has received FIN connection socket, will return 0.

 

What is the impact of the presence of a large number of TIME_WAIT and CLOSE_WAIT?

The kernel maintains more state. Receive ip packets, do hash operations, hlist conflicts are more likely.

 

1. First of all, to clarify what is 2MSL: TCP four times waved to disconnect, the active party to disconnect (here we call the client A) in the receipt of the opposite end (here we call the server B) to send the FIN packet, it will immediately send an ACK response packet and wait for a period of time to ensure that the ACK packet sent by themselves to ensure that the success of the transmission of the network to reach the service side of the B terminal, thus helping the B terminal Normal disconnection (server B can only normally release resources to disconnect after receiving the ACK packet corresponding to the FIN packet sent by itself), the length of this waiting time is 2MSL, calculated from the start of the ACK packet sent by client A. If A receives a new FIN packet sent by server B after sending the ACK packet, it will send a new ACK packet again and re-timed (client B may be unable to send the new packet due to timeout or packet loss, etc.). resend the FIN packet due to various reasons such as timeout or packet loss);
2. Secondly, let's clarify what is MSL: MSL is Maximum Segment Lifetime, it is the longest time for any TCP segment to exist on the network, and TCP messages exceeding this time will be discarded, RFC793 defines the MSL to be 2 minutes, but this is entirely from the engineering consideration, for the current network, different operating systems, TCP implementations can be configured to use a smaller MSL according to the specific network conditions. TCP implementations can be configured to use a smaller MSL according to the specific network conditions;

3. Again, why TCP needs to wait for 2MSL for the fourth wave: client A waits for 2MSL to ensure that the data packet between client A and server B can complete a complete round trip, so if the ACK packet previously sent by A is lost in the network for some reason, server B does not receive client A's ACK packet after the timeout, it will resend the FIN packet. The 2MSL wait time ensures that client A receives a new FIN packet from server B, sends a new ACK packet, and retimes itself;

4. Finally, how to view and configure MSL in LINUX OS: In fact, MSL is not directly configured in LINUX OS, but tcp_fin_timeout is configured, since tcp_fin_timeout=2MSL, so we can view tcp_fin_timeout and infer MSL accordingly: you can view the tcp_fin_timeout with the command sysctl net.ipv4.tcp_fin_timeout, and modify the tcp_fin_timeout with the command sysctl -w net.ipv4.tcp_fin_timeout=30.

Briefly summarized, because the network is unreliable, packets may be lost during transmission may timeout may be disordered, so TCP in order to provide reliability on the basis of the logical virtual connection, in the four handshakes to disconnect the active disconnection of the party needs to wait 2MSL (of course, the three handshakes and four handshakes, as well as the connection process of the confirmation/accumulative confirmation/selection of confirmations, and other mechanisms). (of course three handshakes and four handshakes, as well as acknowledgement/cumulative acknowledgement/selection acknowledgement mechanisms during the connection process, are all for this reason)

 

 

TCP's four swings follow a similar routine.

The active disconnect side is A and the passive disconnect side is B.

First message: A sent FIN

Second message: B Reply ACK

Third message: B sent FIN

At this moment: B unilaterally believes that he has reached a consensus with A, i.e. both parties agree to close the connection.

At this point, can B release the memory resources occupied by this TCP connection? No. B must make sure that A receives its own ACK and FIN.

So B needs to wait quietly for A's fourth message to arrive:

Fourth message: A sends an ACK to acknowledge receipt of B's FIN

When B receives this message, it is considered that both parties have reached a synchronization: both parties know that the connection is ready to be released, and at this point B can safely release the memory resources and port number occupied by this TCP connection.

So passive shutdown B doesn't need any wait time and releases the resource directly.

But, A doesn't know if B receives his ACK or not, A thinks so:

1) If B does not receive its own ACK, it will time out and retransmit the FiN

Then A receives the retransmitted FIN again and will send the ACK again

2) If B receives its own ACK, it will also not send any more messages, including ACKs

Either 1 or 2, A needs to wait, and the maximum value of the waiting time for both cases is to be taken for the worst case scenario to occur, and this worst case scenario is:

Maximum survival time (MSL) for outgoing ACK messages + Maximum survival time (MSL) for incoming FIN messages.

This happens to be 2MSL ( Maximum Segment Life).

Waiting for 2MSL time, A can safely release the TCP occupied resource, port number, which can be used to connect to any server at this time.

Why do we have to wait for 2MSL?

If you don't wait, the released port may reconnect to the just-disconnected server port, so that the old TCP packets still alive in the network may conflict with the new TCP connection packets, resulting in a data conflict.

To avoid this, it is necessary to wait patiently for all the active messages of the network's old TCP connections to die, and a 2MSL time can fulfill this need (albeit very conservatively)!