TCP status migration
You are familiar with the netstat-a command. However, have you noticed that the STATE column displays established, time_wait, close_wait, and so on, in this article, I will elaborate in detail.
Everyone understands that TCP initializes the three-way handshake of the connection: Send the SYN packet, then return the SYN/ACK packet, and then send the ACK packet. The connection is formally established. However, there is a difference here. When the requester receives the SYS/ACK package, the connection starts to be established, and the connection is established only after the third handshake of the requester ends. But do you understand how to close the connection? Four handshakes are required to close the connection: Send the FIN packet, ACK packet, FIN packet, ACK packet, and four handshakes !! Why? Because the TCP connection is full-duplex, I close your connection, and it does not mean that you have closed my connection.
Client TCP status migration:
CLOSED-> SYN_SENT-> ESTABLISHED-> FIN_WAIT_1-> FIN_WAIT_2-> TIME_WAIT-> CLOSED
Server TCP status migration:
CLOSED-> LISTEN-> SYN received-> ESTABLISHED-> CLOSE_WAIT-> LAST_ACK-> CLOSED
When the client starts to connect, the server is still in LISTENING,
After the client sends a SYN packet, it is in the SYN_SENT state, and the server is in the SYS receiving State,
Then confirm the connection status.
When the client requests to close the connection, after the client sends a FIN package, the client enters the FIN_WAIT_1 status and waits for the confirmation package from the other party,
The server sends an ACK packet to the client. After receiving the ACK packet, the client ends the FIN_WAIT_1 status and enters the FIN_WAIT_2 status. Wait for the server to close the request,
The server sends a FIN package and enters the CLOSE_WAIT status,
When the client receives the server's FIN package, the FIN_WAIT_2 State ends, and then a confirmation package is sent to the server's FIN package. Then the client enters TIME_WAIT,
When the server receives the confirmation packet, the CLOSE_WAIT status ends,
At this time, the server actually closes the connection, but the client is still in the TIME_WAIT status,
When will it end? Here I will talk about a new term: 2MSL waiting status. In fact, TIME_WAIT is 2MSL waiting status,
The reason for setting this status is that there is enough time for the ACK packet to reach the server. If the server does not receive the ACK packet, it times out and resends a FIN packet, until the server receives the ACK packet.
The TIME_WAIT status wait time is twice as long as no request is connected after TCP restart.
Have you found a problem: if the other party encounters a problem during the third handshake, for example, when sending a FIN package, I don't know why I lost the package. However, this is always in the FIN_WAIT_2 state, moreover, if TCP/IP does not set the expiration time for this status, it will keep this status. More and more FIN_WAIT_2 statuses will cause system crash.
The problem I encountered above is mainly because the TCP End Process is not completed, resulting in the connection not released. The client is automatically disconnected. The process is as follows:
Client Message Server
Close ()
------ FIN ------->
FIN_WAIT1 CLOSE_WAIT
<----- ACK -------
FIN_WAIT2
Close ()
<------ FIN ------
TIME_WAIT LAST_ACK
------ ACK ------->
CLOSED
CLOSED
Because the Socket of the Server is disabled on the client,
The connection to the server is in the "suspended" status, while the client is in the waiting status for a response.
Typical features of this problem are:
One end is in FIN_WAIT2, and the other end is in CLOSE_WAIT.
However, the root problem is that the program is not well written and needs to be improved.
-------------------------------------------------------------------------
CLOSE_WAIT, TCP cancer, TCP friends.
Reasons for CLOSE_WAIT status generation
First, we know that if our server program APACHE is in the CLOSE_WAIT status, it means the socket is passively closed!
If the CLIENT breaks the current connection, the two parties need four packages to close the TCP connection:
Client ---> FIN ---> Server
Client <--- ACK <--- Server
At this time, the Client is in the FIN_WAIT_2 state, while the Server program is in the CLOSE_WAIT state.
Client <--- FIN <--- Server
When the Server sends FIN to the Client, the Server is set to the LAST_ACK state.
Client ---> ACK ---> Server
When the Client responds to ACK, the socket of the Server is actually set to CLOSED.
The Server program is in the CLOSE_WAIT State, rather than the LAST_ACK state. It indicates that no FIN has been sent to the Client, so it may be that there is still a lot of data to be sent or to be done before closing the connection, as a result, the FIN packet is not sent.
Generally, a CLOSE_WAIT will last for at least two hours. If a rogue specially writes a program that creates a bunch of CLOSE_WAIT for you and consumes your resources, the system will have to solve the crash if it cannot be released.
You can only modify the TCP/IP parameters to shorten the time: modifying the tcp_keepalive _ * series parameters helps solve this problem.
To solve this problem, modify the system parameters. The default system timeout time is 7200 seconds, that is, 2 hours. This is too large. You can modify the following parameters:
Sysctl-w net. ipv4.tcp _ keepalive_time = 30
Sysctl-w net. ipv4.tcp _ keepalive_probes = 2
Sysctl-w net. ipv4.tcp _ keepalive_intvl = 2
Then, run the sysctl command to make the modification take effect.
The connection process is represented by a series of statuses:
LISTEN, SYN-SENT, SYN-RECEIVED, ESTABLISHED, FIN-WAIT-1, FIN-WAIT-2, CLOSE-WAIT, CLOSING, LAST-ACK, TIME-WAIT and CLOSED
The meaning of each status is as follows:
LISTEN-LISTEN for connection requests from remote TCP ports;
SYN-SENT-Wait for a matched connection request after sending the connection request;
SYN-RECEIVED-wait for confirmation of connection requests after receiving and sending a connection request;
ESTABLISHED-indicates an opened connection. data can be transmitted to users;
FIN-WAIT-1-waiting for confirmation of connection interruption requests from remote TCP or previous connection interruption requests;
FIN-WAIT-2-WAIT for connection interruption requests from remote TCP;
CLOSE-WAIT for the connection interruption request from the local user;
CLOSING-waiting for confirmation of remote TCP connection interruption;
LAST-ACK-waiting for confirmation of the original connection interruption request sent to remote TCP;
TIME-WAIT for enough TIME to ensure that the remote TCP receives the confirmation of the connection interruption request;
CLOSED-No connection status;
The TCP connection process is a state transition, prompting the user to call the status transition:
OPEN, SEND, RECEIVE, CLOSE, ABORT, and STATUS
The transmitted data segments, especially those marked as SYN, ACK, RST, and FIN;
There is also timeout. The TCP status changes as mentioned above.
N people know that this figure is helpful for troubleshooting and fixing network or system faults. But how can we keep this figure in our minds? Then, you must have a deep understanding of every state of the image and the conversion process. You must not just stay in the dark. Next, let's explain in detail the 11 States of this image to enhance memory! However, let's review the three-way handshake process of TCP connection establishment and the four-way handshake process of closing the connection.
1. Establish a connection protocol (three-way handshake)
(1) the client sends a TCP packet with a SYN sign to the server. This is packet 1 during the three-way handshake.
(2) The server responds to the client. This is the first packet in the three-way handshake. This packet carries both the ACK mark and SYN mark. Therefore, it indicates the response to the client SYN Packet. It also marks the SYN message to the client and asks whether the client is ready for data communication.
(3) The customer must re-respond to an ACK packet in the service segment, which is packet segment 3.
2. Connection termination protocol (four handshakes)
Because the TCP connection is full-duplex, each direction must be closed separately. This principle is that when one party completes its data sending task, it can send a FIN to end the connection in this direction. Receiving a FIN only means that there is no data flow between the two parties. a tcp connection can still send data after receiving a FIN. First, the party that closes the service will take the initiative to close the service, and the other party will passively close the service.
(1) The TCP client sends a FIN to disable data transmission from the customer to the server (packet segment 4 ).
(2) When the server receives the FIN, it sends back an ACK and confirms that the serial number is 1 (packet segment 5 ). Like SYN, a FIN occupies a sequence number.
(3) The server closes the client connection and sends a FIN to the client (packet segment 6 ).
(4) The customer segment sends back the ACK message for confirmation, and sets the confirmation sequence number to receive the serial number plus 1 (packet segment 7 ).
CLOSED: this is nothing to say, indicating the initial state.
LISTEN: this is also an easy-to-understand status, indicating that a SOCKET on the server is in the listening status and can accept connections.
SYN_RCVD: this status indicates that the SYN message is received. Normally, this status is an intermediate status of the server SOCKET during the three-way handshake session when a TCP connection is established. It is very short, basically, you can hardly see this status with netstat unless you write a client test program and deliberately disable the last ACK packet from the three TCP handshakes. Therefore, when an ACK packet is received from the client, it enters the ESTABLISHED status.
SYN_SENT: this status echo SYN_RCVD. When the client SOCKET executes the CONNECT connection, it first sends the SYN packet, and then it enters the SYN_SENT status, and wait for the server to send 2nd messages in the three-way handshake. SYN_SENT status indicates that the client has sent SYN packets.
ESTABLISHED: This is easy to understand, indicating that the connection has been ESTABLISHED.
FIN_WAIT_1: the real meaning of FIN_WAIT_1 and FIN_WAIT_2 indicate waiting for the other party's FIN message. The difference between the two States is that the FIN_WAIT_1 state is actually when the SOCKET is in the ESTABLISHED State, it wants to actively close the connection and send a FIN packet to the other party, the SOCKET enters the FIN_WAIT_1 state. When the other Party responds to the ACK packet, it enters the FIN_WAIT_2 status. Of course, under normal circumstances, the other party should immediately respond to the ACK packet, regardless of the situation, therefore, the FIN_WAIT_1 status is generally difficult to see, while the FIN_WAIT_2 status is often seen using netstat.
FIN_WAIT_2: The above has explained in detail this status. In fact, the SOCKET in the FIN_WAIT_2 status indicates a semi-connection, that is, either party requires a close connection, but also tells the other party, I have some data to send to you, and close the connection later.
TIME_WAIT: indicates that the other party's FIN message is received, and the ACK message is sent concurrently, so that 2MSL can return to the CLOSED available status. If FIN_WAIT_1 receives a message with both the FIN tag and ACK flag, it can directly enter the TIME_WAIT status without passing through the FIN_WAIT_2 status.
CLOSING: this is a special exception that is rare in actual situations. Under normal circumstances, when you send a FIN packet, it is reasonable to first receive (or simultaneously receive) the ACK packet from the other party and then receive the FIN packet from the other party. However, the CLOSING status indicates that after you send the FIN packet, you have not received the ACK packet from the other party, but have also received the FIN packet from the other party. Under what circumstances will this happen? In fact, it is not difficult to come to the conclusion that if both parties close a SOCKET almost simultaneously, then both parties send FIN packets at the same time, that is, the CLOSING status will appear, indicating that both parties are CLOSING the SOCKET connection.
CLOSE_WAIT: the meaning of this state is actually waiting to be closed. How can this problem be solved? When the other party closes a SOCKET and sends a FIN packet to itself, your system will undoubtedly respond to an ACK packet to the other party, and then enters the CLOSE_WAIT status. Next, in fact, what you really need to consider is to check if you still have data to send to the other party. If not, you can close the SOCKET and send the FIN packet to the other party, that is, close the connection. So what you need to do in CLOSE_WAIT is to wait for you to close the connection.
LAST_ACK: this status is easy to understand. It passively closes the ACK packet sent by one party and waits for the other party after sending the FIN message. After receiving the ACK message, you can enter the CLOSED available status.
Finally, I have two answers. I have analyzed the results (not necessarily 100% correct)
1. Why is the three-way handshake while the four-way handshake when the connection is closed?
This is because the SOCKET in the LISTEN status of the server can respond to ACK and SYN after receiving the SYN Packet connection request) it is sent in a message. However, when the connection is closed, when the other party receives the FIN Message notification, it only indicates that the other party has no data to send to you; but not all your data may have been sent to the other party, therefore, you may not close the SOCKET immediately, that is, you may need to send some data to the other party, and then send the FIN message to the other party to indicate that you agree to close the connection now, therefore, the ACK messages and FIN messages are sent separately in most cases.
2. Why does the TIME_WAIT status still need to wait for 2MSL before it can be returned to the CLOSED state?
This is because, although both parties agree to close the connection, and the four packets of the handshake are also coordinated and sent, the logic can be directly returned to the CLOSED state (just like from SYN_SEND to ESTABLISH State); but because we must assume that the network is unreliable, you cannot guarantee that the last ACK message you sent will be received by the other party. Therefore, the SOCKET in the LAST_ACK status of the other party may not receive the ACK message because of timeout, and resend the FIN message, therefore, the TIME_WAIT status is used to resend the possibly lost ACK message and ensure this.
When the connection is disconnected, when the left side that initiates the active shutdown sends a FIN,
The passive shutdown on the right side will respond to an ACK, which is a TCP response instead of sent by the application,
In this case, the party that passively closes is in the CLOSE_WAIT state.
If the party that is passively closed does not call closesocket at this time, it will not send the next FIN, so that it is always in CLOSE_WAIT.
Only when the party that is passively closed calls closesocket will it send a FIN to the party that is actively closed, and change its status to LAST_ACK.
For example, the client is passively closed.
When the other party calls closesocket, your program is
Int nRet = recv (s ,....);
If (nRet = SOCKET_ERROR)
{
// Closesocket (s); & #160;
Return FALSE;
}
Many people forget the sentence closesocket, which is too common.
My understanding,
When the active closing party sends a FIN to the passive closing side, the TCP of the passive closing side immediately responds to an ACK and submits an ERROR to the application,
Cause the above SOCKET send or recv to return SOCKET_ERROR.
Normally, if closesocket is called after SOCKET_ERROR is returned, the TCP of the passive disabled party will send a FIN and its status will change to LAST_ACK.
There are a lot of close_wait examples and solutions on the server (the example is found on the internet, basically similar)
$/Usr/sbin/lsof-I | grep 6800
$/Usr/sbin/lsof-I | grep 6800
Oracle 22725 oracle9i 3u IPv4 18621468 TCP RHEL3: 6800 (LISTEN)
Oracle 22725 oracle9i 4u IPv4 18621469 TCP RHEL3: 6800-> RHEL3: 2174 (CLOSE_WAIT)
Oracle 22725 oracle9i 8u IPv4 18621568 TCP RHEL3: 6800-> RHEL3: 2175 (CLOSE_WAIT)
Oracle 22725 oracle9i 9u IPv4 18621578 TCP RHEL3: 6800-> RHEL3: 2176 (CLOSE_WAIT)
Oracle 22726 oracle9i 3u IPv4 18621468 TCP RHEL3: 6800 (LISTEN)
Oracle 22726 oracle9i 4u IPv4 18621469 TCP RHEL3: 6800-> RHEL3: 2174 (CLOSE_WAIT)
Oracle 22726 oracle9i 8u IPv4 18621568 TCP RHEL3: 6800-> RHEL3: 2175 (CLOSE_WAIT)
Oracle 22726 oracle9i 9u IPv4 18621578 TCP RHEL3: 6800-> RHEL3: 2176 (CLOSE_WAIT)
$ Kill-9 22725
#22725,227 26 is the process number (PID) that uses port 6800 ).
$/Usr/sbin/lsof-I | grep 6800
When a process is killed, all the link handles occupied are released.
The cause of this problem is everywhere on the Internet, that is, the Client of the Socket exits if there is an exception and no Close occurs.