What are the main causes of network disconnection? To sum up, there are two main types:
1. ClientProgramException.
In this case, we can handle it well, because the client program will cause a socket exception of connectionreset on the server side (that is, the 10054 exception in Winsock2) when it exits abnormally ). You only need to handle this exception on the server.
2. network link exceptions.
Such as network cable disconnection, switch power loss, and client machine power loss. When these conditions occur, the server will not have any exceptions. In this case, the aboveCodeYou cannot handle this situation. This is the case in msdn. I will post the original article of msdn here:
If you need to determine the current status of the connection, please do not block, zero-byte send call. If the call is successful or the waewouldblock error code (10035) is triggered, the socket is still in the connection status; otherwise, the socket is no longer in the connection status.
However, in practical applications, I found that this method described by msdn is often ineffective and cannot detect that the network has been disconnected abnormally. What should we do?
We know that TCP has a connection detection mechanism, that is, if no data is transmitted within the specified time (generally 2 hours), a keep-alive datagram will be sent to the peer end, the serial number used is the serial number of the last byte of the last sent packet. If the peer receives the data, it returns a tcp ack to confirm that the byte has been received, the connection is not disconnected. If the response is not received by the other party for a period of time, the system will try again. After several retries, it will send a reset to the peer end and disconnect the connection.
In Windows, the first test is performed every two seconds after the last data is sent. If no response is received for five times, the connection will be disconnected. But two hours is obviously too long for our project. We must shorten this time. So what should we do? I want to use the iocontrol () function of the socket class. Let's take a look at what this function can do:
Use iocontrolcode enumeration to specify the control code and set the low-level operation mode for the socket.
Namespace: system. net. Sockets
Assembly: system (in system. dll)
Syntax
C #
Public int iocontrol (
Iocontrolcode,
Byte [] optioninvalue,
Byte [] optionoutvalue
)
Parameters
Iocontrolcode
An iocontrolcode value that specifies the control code for the operation to be executed.
Optioninvalue
Byte array, which contains the input data required by the operation.
Optionoutvalue
Byte array, which contains the output data returned by the operation.
Return Value
The number of bytes in the optionoutvalue parameter.
Struct Tcp_keepalive
...{
U_long Onoff; // Enable keep-alive?
U_long KeepAliveTime; // How long will the first probe start (unit: milliseconds)
U_long keepaliveinterval; // Detection interval (unit: milliseconds)
};
In C #, we directly use a byte array to pass it to the function:
Code
Uint Dummy = 0 ;
Byte [] Inoptionvalues = New Byte [Marshal. sizeof (dummy) * 3 ];
Bitconverter. getbytes (( Uint ) 1 ). Copyto (inoptionvalues, 0 ); // Enable keep-alive?
Bitconverter. getbytes (( Uint ) 5000 ). Copyto (inoptionvalues, Marshal. sizeof (dummy )); // How long does it take to start the first probe?
Bitconverter. getbytes (( Uint ) 5000 ). Copyto (inoptionvalues, Marshal. sizeof (dummy) * 2 ); // Detection Interval
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 (effececallback), Info );
}
In the previous example, modify
Code
/// <Summary>
/// Method for waiting for client connection
/// </Summary>
Void Writeconnetion ()
{
While ( True )
{
Uint Dummy = 0 ;
Byte [] Inoptionvalues = New Byte [Marshal. sizeof (dummy) * 3 ];
Bitconverter. getbytes (( Uint ) 1 ). Copyto (inoptionvalues, 0 ); // Enable keep-alive?
Bitconverter. getbytes (( Uint ) 5000 ). Copyto (inoptionvalues, Marshal. sizeof (dummy )); // How long does it take to start the first probe?
Bitconverter. getbytes (( Uint ) 5000 ). Copyto (inoptionvalues, Marshal. sizeof (dummy) * 2 ); // Detection Interval
Try
{
Socket s = _ Server. Accept ();
S. iocontrol (iocontrolcode. keepalivevalues, inoptionvalues, null );
User user = New User ();
User. userid = Guid. newguid (). tostring ();
User. mysocket = S;
S. beginreceive (user. MSG, 0 , User. msg. length, socketflags. None, New Asynccallback (recivecallback), user ); // Send a request for receiving information to the system. recivecallback is the callback function.
}
Catch (System. Exception ex)
{
}
}
}