다음을 통해 공유


C# - The use of Keep-Alive to deal socket abnormal disconnection method

Internet disruptions is very common in writing programs in fact, and very detailed processing skills, when there are some ways to deal with in dealing with these exceptions, and now write and share with you.

The reasons for the disconnection of the network are summarized in the following two types:

1.The client program exception.

For this situation, we are very good to deal with, because the client program will withdraw from the server will trigger ConnectionReset Socket exception (that is, WinSock2 10054 exception). As long as the server can handle this exception.

2. The network is abnormal.

Such as: the network is not connected, the switch is running bad, the client machine failure. When the situation occurs when the server does not appear any exception. So the above code can not handle this situation. For this situation in MSDN which is handled here, I posted here the original MSDN:

https://msdn.microsoft.com/en-us/library/system.net.sockets.socket.connected(v=vs.110).aspx

「The value of the Connected property reflects the state of the connection as of the most recent operation. If you need to determine the current state of the connection, make a nonblocking, zero-byte Send call. If the call returns successfully or throws a WAEWOULDBLOCK error code (10035), then the socket is still connected; otherwise, the socket is no longer connected.」

However, We found that MSDN in this treatment method is often ineffective in practical applications(Sorry about that), can not detect the network has been disconnected. What should we do?

We know that TCP has a connection detection mechanism, that is, if the specified time (also called keep-alive, see this article, usually 2 hours) no data transmission, will send a Keep- The serial number used is the serial number of the last byte of the last message that was issued. f the receiver receives this data, send back a TCP ACK, confirm that the byte has been received, so that this connection is not broken. If you do not receive a response from time to time, you will try again, try again a few times, send a reset to the peer, and then disconnect the connection.

In Windows, the first probe is in the last two data transmission time, and then every 1 second detection time, a total of 5 times to detect, if 5 did not receive a response, then it will disconnect the connection. But 2 hours for our project is obviously too long. We must shorten this time. So what should we do? I want to use the Socket class IOControl () function. Let's take a look at what this function can do:

Use the IOControlCode enumeration to specify the control code to set the low-order operation mode for the Socket.

System.Net.Sockets 
System(In system.dll)
public int  IOControl ( 
   IOControlCode ioControlCode, 
   byte[] optionInValue, 
   byte[] optionOutValue 
)

parameter

ioControlCode 
An IOControlCode value that specifies the control code for the action to be performed.

optionInValue 
An array of Byte types that contains input data for operational requirements.

optionOutValue 
Byte type of array containing the output data returned by the operation.

return value
The number of bytes in the optionOutValue parameter.

Such as:

socket.IOControl(IOControlCode.KeepAliveValues, inOptionValues, null);
We have to understand is inoptionValues definition, in C + + where it is a structure.

Let's take a look at this structure:

struct tcp_keepalive 
{ 
    u_long  onoff; //Whether to enable Keep-Alive
    u_long  keepalivetime; //How long does it take to start the first probe (in milliseconds)
    u_long  keepaliveinterval; //Detection time interval (in milliseconds)
};

In C #, we pass directly to a function with a Byte array:

uint dummy = 0;
byte[] inOptionValues = new byte[Marshal.SizeOf(dummy) * 3];
BitConverter.GetBytes((uint)1).CopyTo(inOptionValues, 0);//Whether to enable Keep-Alive
BitConverter.GetBytes((uint)5000).CopyTo(inOptionValues, Marshal.SizeOf(dummy));//How long to start the first detection
BitConverter.GetBytes((uint)5000).CopyTo(inOptionValues, Marshal.SizeOf(dummy) * 2);//Detection interval

Specific implementation code:

public static void AcceptThread()  
{  
    Thread.CurrentThread.IsBackground = true;  
    while (true)  
    {  
        uint dummy = 0;  
        byte[] inOptionValues = new byte[Marshal.SizeOf(dummy) * 3];  
        BitConverter.GetBytes((uint)1).CopyTo(inOptionValues, 0);  
        BitConverter.GetBytes((uint)5000).CopyTo(inOptionValues, Marshal.SizeOf(dummy));  
        BitConverter.GetBytes((uint)5000).CopyTo(inOptionValues, Marshal.SizeOf(dummy) * 2);  
        try 
        {  
            Accept(inOptionValues);  
        }  
        catch { }  
    }  
}
private static void Accept(byte[] inOptionValues)
{
    Socket socket = Public.s_socketHandler.Accept();
    socket.IOControl(IOControlCode.KeepAliveValues, inOptionValues, null);
    UserInfo info = new UserInfo();
    info.socket = socket;
    int id = GetUserId();
    info.Index = id;
    Public.s_userList.Add(id, info);
    socket.BeginReceive(info.Buffer, 0, info.Buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallBack), info);
}

This method is effective, more efficient than sending data at regular intervals, the code is also short, in Unix and other operating systems can really set the number of retransmissions, but in the Windows operating system, only by modifying the registry to set the number of retransmission. Can not set a separate Socket object.

And KeepAliveValues suggested that Windows 2000 or later to use, this must be used in the erection of IIS Server System must be noted that the place.