Terminating a connection takes 4 handshakes. This is caused by a semi-shutdown of TCP (Half-close). Since a TCP connection is full-duplex (that is, the data can be passed simultaneously in two directions, it can be understood as a separate channel in the opposite direction of two), each direction must be closed separately. The principle is that when a party completes its data sending task, it can send a fin to terminate the connection. When one side receives a fin, the kernel lets the read return to the end to notify the other end of the application layer that the data transfer to the port has been terminated. Sending fin is usually the result of the application layer closing the socket.
For example, a TCP client sends a fin to turn off data transfer from the client to the server.
What is the effect of semi-shutdown on the server? Let's take a look at the following TCP state conversion diagram
TCP Status Load-change diagram
First, the above illustration is explained:
CLOSED: Indicates the initial state. The same for both server and C clients.
LISTEN: Indicates the listening state. The server has called the Listen function and can start the accept connection.
Syn_sent: Indicates that the client has sent a SYN message. When the client calls the Connect function to initiate a connection, it first sends a SYN to the server, then enters the syn_sent state itself, and waits for the server to send Ack+syn.
SYN_RCVD: Indicates that the server received the client to send the SYN message. After the server receives this message, it enters the SYN_RCVD state and then sends the Ack+syn to the client.
Established: Indicates that the connection has been established successfully. The server enters this state after sending the Ack+syn, and the client receives an ACK and enters that state.
Fin_wait_1: Indicates active shutdown of the connection. Whichever side calls the close function to send fin messages will enter this state.
Fin_wait_2: Indicates that the passive shut-down party agrees to close the connection. When the active shut-down connector receives an ACK returned by the passive shutdown, it enters that state.
Time_wait: To receive the other's fin message and send an ACK message, just wait 2MSL to return to the closed state. If the fin_wait_1 state, received the other side with the FIN flag and the ACK sign of the message, you can go directly into the time_wait state, without having to go through the fin_wait_2 state.
CLOSING: Indicates that both sides close the connection at the same time. If both sides call the close function almost at the same time, there will be a case where both sides send fin messages at the same time, the closing state will appear, indicating that both sides are closing the connection.
Close_wait: Indicates that the passive shut-down party waits for shutdown. When the other side calls the close function to send the FIN message, the response to the other ACK message, at this time into the close_wait state.
Last_ack: Indicates that the passive shut-off party sends a fin message, waits for the other party's ACK message status, and then enters the closed state when the ACK is received.
The above states for three-time handshake and four-time handshake:
When the client actively shuts down, the fin packet is issued, the server's ACK is received, and the client stays in the FIN_WAIT2 state. The server receives fin, sends an ACK, and stays in the colse_wait state.
This close_wait state is very annoying, it lasts for a very long time, the server side if a large number of colse_wait state sockets, it is possible to run out of server resources, and thus unable to provide services.
So, on the server is how to produce a large number of out-of-control colse_wait state socket it. Let's track it down.
One obvious reason is that the server did not continue to send fin packets to the client.
Why the server does not send fin, may be the need for business implementation, now is not the time to send fin, because the server also has data to send to the client, sent out naturally through the system call to send fin, this scene is not mentioned above the continuous colse_wait State, This is within the controlled range.
So what is the reason for this, we introduced two system calls close (SOCKFD) and shutdown (sockfd,how) and then down analysis.
Here, a definite concept needs to be defined----a process opens a socket, and the sockfd of the socket is inherited when the process then derives the child process. The socket is a system-level object, and now the result is that the socket is opened by two processes, and the reference count of this socket becomes 2.
Continue to say that the two system calls to the socket closed.
When Close (SOCKFD) is called, the kernel checks the reference count on the socket corresponding to this FD. If the reference count is greater than 1, the reference count is reduced by 1 and then returned. If the reference count equals 1, the kernel will actually close the TCP connection by sending the fin.
When you call Shutdown (SOCKFD,SHUT_RDWR), the kernel does not check the reference count on the corresponding socket of this FD and directly closes the TCP connection by sending Fin.
Now it should be the truth, maybe the server implementation is a bit problematic, the parent process opens the socket, and then uses the derived child process to process the business, the parent process continues to listen for network requests, never terminates. When the client sends the FIN over, read returns 0 for the child process that handles the business, the child process discovers that the peer is closed, and directly calls Close () to close the local side. In fact, just making the socket reference count minus 1,socket is not turned off. This leads to a close_wait socket in the system ...
How to avoid such a situation happen.
The process of closing a child process should be this:
Shutdown (SOCKFD,SHUT_RDWR);
Close (SOCKFD);
This processing, the server fin will be issued, the socket into the Last_ack state, waiting for the final ACK arrival, you can enter the initial state closed.
Add a description of the function of shutdown ()
Use shutdown system calls under Linux to control how sockets are closed
int shutdown (Intsockfd,int how);
Parameter how allows you to choose the following methods for shutdown operations:
SHUT_RD: Closes the read end of the connection. That is, the socket no longer accepts data, and any data currently in the socket accept buffer will be discarded. The process will not be able to make any read operations on the socket. Any data that is received after the call to the TCP socket is acknowledged and then discarded.
SHUT_WR: Closes the write end of the connection.
Shut_rdwr: equivalent to calling shutdown two times: first with SHUT_RD, then SHUT_WR
Attention:
In a multi-process, if a process is shutdown (SFD, shut_rdwr), other processes will not be able to communicate. If a process close (SFD) will not affect other processes.