http://www.cnblogs.com/wzd24/archive/2007/05/22/755050.html
最近我负责一个IM项目的开发,服务端和客户端采用TCP协议连接。服务端采用C#开发,客户端采用Delphi开发。在服务端开发中我碰到了各种各样的网络异常断开现象。在处理这些异常的时候有了一些心得,现在写出来和大家分享一下。

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

1、客户端程序异常。

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

2、网络链路异常。

  如:网线拔出、交换机掉电、客户端机器掉电。当出现这些情况的时候服务端不会出现任何异常。这样的话上面的代码就不能处理这种情况了。对于这种情况在MSDN里面是这样处理的,我在这里贴出MSDN的原文:

如果您需要确定连接的当前状态,请进行非阻止、零字节的 Send 调用。如果该调用成功返回或引发 WAEWOULDBLOCK 错误代码 (10035),则该套接字仍然处于连接状态;否则,该套接字不再处于连接状态。

  但是我在实际应用中发现,MSDN说的这种处理方法在很多时候根本无效,无法检测出网络已经异常断开了。那我们该怎么办呢?

  我们知道,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);
        }

好了,这样就成功了。

转载于:https://www.cnblogs.com/jambol/archive/2007/07/31/837946.html

在C#中利用Keep-Alive处理Socket网络异常断开的方法 (转)相关推荐

  1. 在C#中利用Keep-Alive处理Socket网络异常断开的方法

    最近我负责一个IM项目的开发,服务端和客户端采用TCP协议连接.服务端采用C#开发,客户端采用Delphi开发.在服务端开发中我碰到了各种各样的网络异常断开现象.在处理这些异常的时候有了一些心得,现在 ...

  2. MVC中利用ViewBag传递Json数据时的前端处理方法

    ** MVC中利用ViewBag传递Json数据时的前端处理方法 ** 用viewBag传递Json字符串到前端时,json字符串中的"会被转义为& quot,前端处理方法为@Htm ...

  3. JQuery中使用Ajax赋值给全局变量失败异常的解决方法,jqueryajax

    我们在用JQuery的Ajax从后台提取数据后想把它赋值给全局变量,但是却怎么都赋不进,为什么呢? 原因其实很简单,我们用的Ajax是异步操作,也就是说在你赋值的时候数据还没提取出来,你当然赋不进去, ...

  4. 常见的Socket网络异常场景分析

    原创:打码日记(微信公众号ID:codelogs),欢迎分享,转载请保留出处. 简介 在目前微服务的背景下,网络异常越来越常见了,而有一些网络异常非常模糊,理解什么情况下会导致什么异常,还是有一定难度 ...

  5. python中语法错误-Python语法错误与异常及异常处理方法

    回顾 在Python进阶记录之基础篇(二十)中,我们介绍了Python面向对象中的类方法和静态方法,以及类中拥有特殊功能的魔法函数.需要重点掌握类方法和静态方法的概念和基本用法,理解魔法函数的作用冰女 ...

  6. CTF pwn中利用pwntools加载不同版本libc调试程序的方法

    在网上找到了很多加载libc的帖子,终于自己走通了一次,现在把方法和资源都整理一下 一.解决方案 python利用pwntools的代码 from pwn import * import pwnlib ...

  7. android+网络下载资源,【已解决】Android中利用HttpClient等库实现网络文件下载

    [问题] 已经获得了Songtaste中歌曲的地址,比如: 中的真实下载地址是: 然后现在想要去下载这样的文件到Android手机的本地某个文件夹中. [解决过程] 1.其中,关于自动处理Cookie ...

  8. 使用SQLDMO中“接口SQLDMO.Namelist 的 QueryInterface 失败”异常的解决方法

    SQLDMO(SQL Distributed Management Objects,SQL分布式管理对象),它封装 Microsoft SQL Server 数据库中的对象.它允许我们通过COM对象, ...

  9. python中exception类的_Python自定义一个异常类的方法

    如何实现自定义一个异常 python内置了许多异常类,为编写代码划定红线,才使调试代码时能及时发现错误.那么我们编写一个模块也可以为使用此模块者划定红线,来约束使用者可用哪些数据,这就需要自定义异常类 ...

  10. KDD CUP 99利用决策分类树进行网络异常检测

    import pandas as pd import numpy as np import matplotlib.pyplot as plt 数据导入与数据探索 数据导入 df=pd.read_csv ...

最新文章

  1. 专家解读下一代互联网创新模式,核心技术是根本
  2. Entity Framework 6 Recipes 2nd Edition(10-3)译 - 返回结果是一个标量值
  3. Too Many Segments (easy version) CodeForces - 1249D1(贪心+差分)
  4. nhinx php 调优,高流量站点NGINX与PHP-fpm配置优化
  5. 简单使用AutoMapper实现DTO转换
  6. python怎么建立替换_Python-如何搜索和替换文件中的文本?
  7. Hadoop hdfs上传文件报错解决
  8. Entity Framework 与 面向对象
  9. 把代码写成艺术,真正体会面向对象编程思想
  10. 数据库系统工程师教程 (第三版)前言
  11. WAPI在校园网应用中的证书安装
  12. 飞机加油游戏 --- 我的易术
  13. JAVA算法:三角形周长(JAVA版本算法)
  14. 一款令人发指的Linux监控软件
  15. Python 实战案例--计算圆、矩形的周长和面积
  16. Codeforces 513F1 513F2 Scaygerboss 网络流
  17. 职场,社恐的终极噩梦
  18. 第十三次CCF认证经历
  19. 同方TF32A09加密芯片算法参数
  20. c语言水仙花数256,c语言学习:求水仙花数

热门文章

  1. 医疗健康领域的短文本解析探索----文本纠错
  2. 原价399,限时1元!7天人工智能入门训练营:带你从0掌握机器学习算法!
  3. 一文总结熵,交叉熵与交叉熵损失
  4. 百面机器学习—11.集成学习(GBDT、XGBoost)面试问题总结
  5. 机器学习算法基础6-模型保存与加载、逻辑回归、Kmeans(聚类)
  6. pytorch之深度学习
  7. C语言手写模拟字符串String类
  8. 豆瓣评分9.3的经典Kubernetes图书推出中文版,学习K8S更方便了
  9. 博文视点新书快讯第78期
  10. DLL load failed: 找不到指定模块\Failed to load the native TensorFlow runtime解决方法