The reason for the generation of the CLOSE_WAIT state [transfer]

This article is reproduced from: https://www.cnblogs.com/kevin-wu/archive/2006/11/27/574369.html Author: kevin-wu Please indicate the statement when reprinting.


The reason for the generation of the CLOSE_WAIT state First of all, we know that if our Client program is in the CLOSE_WAIT state, the socket is passively closed !

Because if the server side actively disconnects the current connection, then the two parties need four packets to close the TCP connection:

       Server  --->  FIN  --->  Client

       Server  <---  ACK  <---  Client

    At this time, the server side is in the FIN_WAIT_2 state; and our program is in the CLOSE_WAIT state.

       Server  <---  FIN  <---  Client

At this time, the Client sends a FIN to the Server, and the Client is placed in the LAST_ACK state.

        Server  --->  ACK  --->  Client

The Server responds with an ACK, and then the Client's socket is actually set to the CLOSED state.

 

Our program is in the CLOSE_WAIT state instead of the LAST_ACK state, indicating that the FIN has not been sent to the Server, so it may be that there is still a lot of data to be sent or other things to do before the connection is closed, resulting in the FIN packet not being sent.

 

The reason is known, so why not send a FIN packet, is there so much to do before closing its own connection?

For example, elssann said that when the other party calls closesocket, my program is calling recv. At this time, it is possible that I did not receive the FIN packet sent by the other party, but an ACK packet was sent back by TCP, so I socketed here. Word enters CLOSE_WAIT state.

Therefore, he suggested to judge whether the return value of the recv function has been wrong, and if so, close the socket actively, so as to prevent the FIN packet from not being received.

Because we have set the recv timeout to 30 seconds earlier, if it really times out, the error received here should be WSAETIMEDOUT, and the connection can also be actively closed in this case.

 

One more question, why are thousands of connections in this state? During that time, did the server always actively remove our connection?

 

No matter what, we must prevent similar situations from happening again!

First, we need to ensure that the original port can be reused, which can be done by setting the SO_REUSEADDR socket option:


Before reusing the local address and port
, I always used a new port, which caused thousands of ports to enter the CLOSE_WAIT state. If this embarrassing situation happens next time, I hope to add a limit, but the current port is in CLOSE_WAIT state!

calling

sockConnected = socket (AF_INET, SOCK_STREAM, 0);

After that, we want to set options for that socket to reuse:

/// Allow reuse of local addresses and ports:

/// The advantage of this is that even if the socket is disconnected, calling the previous socket function will not occupy another, but will always be a port

/// This prevents the socket from being connected all the time, then according to the original practice, the port will be changed continuously.

int nREUSEADDR = 1;

setsockopt(sockConnected,

              SOL_SOCKET,

              SO_REUSEADDR,

              (const char*)&nREUSEADDR,

              sizeof(int));
 

The textbook says this: So, if the server shuts down or exits, causing the local address and port to be in the TIME_WAIT state, then SO_REUSEADDR is very useful.

Maybe we can't avoid being frozen in the CLOSE_WAIT state and never appear, but at least we can guarantee that no new ports will be occupied.

Second, we want to set the SO_LINGER socket option:

Graceful shutdown or forced shutdown?
LINGER means "to procrastinate".

By default (Win2k), SO_DONTLINGER socket option is 1; SO_LINGER option is, linger is {l_onoff: 0, l_linger: 0}.

If closesocket() is called during the process of sending data (send() has not been completed, and data has not been sent), the usual measure we used in the past was to "close calmly":

Because before exiting the service or every time the socket is re-established, I will call

/// Turn off the two-way communication first

     shutdown(sockConnected, SD_BOTH);

     /// For safety, close the old connection before establishing a socket connection each time

closesocket(sockConnected);

 

We're going to do this this time:

Set SO_LINGER to zero (that is, the l_onoff field in the linger structure is set to non-zero, but l_linger is 0), so you don't have to worry about the closesocket call entering the "locked" state (waiting for completion), regardless of whether there is queued data that is not sent or not acknowledged. . This way of closing is called a "forced close" because the socket's virtual circuit is reset immediately and any data that has not yet been sent is lost. All calls to recv() on the remote end fail with a WSAECONNRESET error.

Set this option after connect successfully establishes a connection:

linger m_sLinger;

m_sLinger.l_onoff = 1; // (It is allowed to stay when closesocket() is called, but there is still data that has not been sent)

m_sLinger.l_linger = 0; // (The allowed time to stay is 0 seconds)

setsockopt(sockConnected,

         SOL_SOCKET,

         SO_LINGER,

         (const char*)&m_sLinger,

         sizeof(linger));
 

 

Conclusion
Maybe we can't avoid the CLOSE_WAIT state freeze again, but we will minimize the impact, and hope that the reuse socket option will enable the CLOSE_WAIT state to be kicked off the next time the connection is re-established.


What I mean is: when one party closes the connection, the other party does not detect it, which leads to the appearance of CLOSE_WAIT. Last time, a friend of mine did the same. He wrote a client to connect with APACHE. When APACHE disconnected the connection , he didn't detect it, and CLOSE_WAIT appeared. Later, I asked him to detect this place. After he added the code to call closesocket, this problem was eliminated.
If CLOSE_WAIT still appears before you close the connection, it is recommended that you cancel the shutdown call and try closesocket on both sides.


another question:

For example,
when the client logs in to the server and sends an authentication request, the server receives the data, verifies the identity of the client, and finds that the password is incorrect. At this time, the general practice of the server should be to send an incorrect password first. information to the client, and then disconnect the connection.

If
m_sLinger.l_onoff = 1;
m_sLinger.l_linger = 0;
is set in this way, in many cases, the client will not receive the password error message at all, and the connection will be disconnected.

 


The reason for the occurrence of CLOSE_WAIT is very simple, that is, a party did not detect this error and did not execute closesocket after the network connection was disconnected, which led to the realization of this state, which can be clearly seen in the state transition diagram of the TCP/IP protocol. At the same time, there is another one called TIME_WAIT corresponding to this.

In addition, setting SO_LINGER of SOCKET to 0 seconds to delay (ie close immediately) is detrimental in many cases.
Also, making ports reusable is an unsafe method of network programming.

 

Can you explain please see here
http://blog.csdn.net/cqq/archive/2005/01/26/269160.aspx

 

Look at this picture again:

http://tech.ccidnet.com/pub/attachment/2004/8/322252.png

When disconnecting,
when the party on the left that initiates the active shutdown sends a FIN, the party on the right that is passively closed should respond with an ACK, which is responded by TCP, not the application. At this time, passive shutdown The side is in CLOSE_WAIT state. If the passively closed party does not continue to call closesocket at this time, then he will not send the next FIN, resulting in himself always in CLOSE_WAIT. Only if the passively closed party calls closesocket, a FIN will be sent to the actively closed party, and at the same time, its state will be changed to LAST_ACK.



For example, the passive shutdown is the client. . .

When the other party calls closesocket, your program is

int nRet = recv(s,....);
if (nRet == SOCKET_ERROR)
{
// closesocket(s);
return FALSE;
}

Many people just forget the phrase closesocket, this kind of code is too common.

As I understand it, when the actively closed side sends FIN to the passively closed side, the TCP on the passively closed side immediately responds with an ACK, and at the same time submits an ERROR to the above application, causing the above SOCKET send or recv to return SOCKET_ERROR, Under normal circumstances, if the above calls closesocket after returning SOCKET_ERROR, then the TCP of the passively closed party will send a FIN, and its state will change to LAST_ACK.


Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324290633&siteId=291194637