C# 检测网络异常断开(非正常通信中断)

来源:互联网 发布:qq mac版怎么更新 编辑:程序博客网 时间:2024/03/29 23:29

网络异常断开原因主要有那些呢?归纳起来主要有以下两种:

1、客户端程序异常。

  对于这种情况,我们很好处理,因为客户端程序异常退出会在服务端引发ConnectionReset的Socket异常(就是WinSock2中的10054异常)。只要在服务端处理这个异常就可以了。

2、网络链路异常。

  如:

网络异常断开原因主要有那些呢?归纳起来主要有以下两种:

1、客户端程序异常。

  对于这种情况,我们很好处理,因为客户端程序异常退出会在服务端引发ConnectionReset的Socket异常(就是WinSock2中的10054异常)。只要在服务端处理这个异常就可以了。

2、网络链路异常。

  如:网线拔出、交换机掉电、客户端机器掉电。当出现这些情况的时候服务端不会出现任何异常。那我们该怎么办呢?

  我们知道,TCP有一个连接检测机制,就是如果在指定的时间内(一般为2个小时)没有数据传送,会给对端发送一个Keep-Alive数据报,使用的序列号是曾经发出的最后一个报文的最后一个字节的序列号,对端如果收到这个数据,回送一个TCP的ACK,确认这个字节已经收到,这样就知道此连接没有被断开。如果一段时间没有收到对方的响应,会进行重试,重试几次后,向对端发一个reset,然后将连接断掉。

  在Windows中,第一次探测是在最后一次数据发送的两个小时,然后每隔1秒探测一次,一共探测5次,如果5次都没有收到回应的话,就会断开这个连接。但两个小时对于我们的项目来说显然太长了。我们必须缩短这个时间。那么我们该如何做呢?我要利用Socket类的IOControl()函数。我们来看看这个函数能干些什么:

 

使用   IOControlCode   枚举指定控制代码,为   Socket   设置低级操作模式。  

命名空间:System.Net.Sockets  
程序集:System(在   system.dll   中)  

语法  

C#  
public   int   IOControl   (  
IOControlCode   ioControlCode,  
byte[]   optionInValue,  
byte[]   optionOutValue  
)  


参数  
ioControlCode  
一个   IOControlCode   值,它指定要执行的操作的控制代码。  

optionInValue  
Byte   类型的数组,包含操作要求的输入数据。  

optionOutValue  
Byte   类型的数组,包含由操作返回的输出数据。  

返回值  
optionOutValue   参数中的字节数。  

如:
socket.IOControl(IOControlCode.KeepAliveValues,   inOptionValues,   null);
我们要搞清楚的就是inOptionValues的定义,在C++里它是一个结构体。我们来看看这个结构体:

struct   tcp_keepalive  {  
        u_long     onoff;   //是否启用Keep-Alive
        u_long     keepalivetime;   //多长时间后开始第一次探测(单位:毫秒)
        u_long     keepaliveinterval;   //探测时间间隔(单位:毫秒)
};

在C#中,我们直接用一个Byte数组传递给函数:

uint   dummy   =   0;
byte[]   inOptionValues   =   new   byte[Marshal.SizeOf(dummy)   *   3];
BitConverter.GetBytes((uint)1).CopyTo(inOptionValues,   0);//是否启用Keep-Alive
BitConverter.GetBytes((uint)5000).CopyTo(inOptionValues,   Marshal.SizeOf(dummy));//多长时间开始第一次探测
BitConverter.GetBytes((uint)5000).CopyTo(inOptionValues,   Marshal.SizeOf(dummy)   *   2);//探测时间间隔

具体实现代码:

                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);
                }

 

原创粉丝点击