部分信息可以看UNIX网络编程第157页,

摘录过来:

在一个正常的TCP连接上,当我们用无限等待的方式调用下面的Recv或Send的时候:

ret=recv(s,&buf[idx],nLeft,flags);

ret=send(s,&buf[idx],nLeft,flags);

如果TCP连接被对方正常关闭,也就是说,对方是正确地调用了closesocket(s)或者shutdown(s)的话,那么上面的Recv或Send调用就能马上返回,并且报错。这是由于closesocket(s)或者shutdown(s)有个正常的关闭过程,会告诉对方“TCP连接已经关闭,你不需要再发送或者接受消息了”。但是,如果是网线突然被拔掉,TCP连接的任何一端的机器突然断电或重启动,那么这时候正在执行Recv或Send操作的一方就会因为没有任何连接中断的通知而一直等待下去,也就是会被长时间卡住。这种情形解决的办法:

1>自己编写心跳包程序

简单的说也就是在自己的程序中加入一条线程,定时向对端发送数据包,查看是否有ACK,如果有则连接正常,没有的话则连接断开

2>启动TCP编程里的keepAlive机制

其实keepalive的原理就是TCP内嵌的一个心跳包,

以服务器端为例,如果当前server端检测到超过一定时间(默认是 7,200,000 milliseconds,也就是2个小时)没有数据传输,那么会向client端发送一个keep-alive packet(该keep-alive packet就是ACK和当前TCP序列号减一的组合),此时client端应该为以下三种情况之一:

1. client端仍然存在,网络连接状况良好。此时client端会返回一个ACK。server端接收到ACK后重置计时器,在2小时后再发送探测。如果2小时内连接上有数据传输,那么在该时间基础上向后推延2个小时。

2. 客户端异常关闭,或是网络断开。在这两种情况下,client端都不会响应。服务器没有收到对其发出探测的响应,并且在一定时间(系统默认为1000 ms)后重复发送keep-alive packet,并且重复发送一定次数(2000 XP 2003 系统默认为5次, Vista后的系统默认为10次)。

3. 客户端曾经崩溃,但已经重启。这种情况下,服务器将会收到对其存活探测的响应,但该响应是一个复位,从而引起服务器对连接的终止。

对于实用程序来说,2小时的空闲时间太长。因此,我们需要手工开启Keepalive功能并设置合理的Keepalive参数。在XP和WIN2003系统上,可以针对单独的socket来设置,但是在windows 2000,不能单独设置,如果设置,那么影响是整个系统的所有socket。

了解了keep alive大致的原理,下来看看在程序中怎么用,怎么设置参数:

[cpp] view plaincopy
  1. #include <mstcpip.h>
  2. BOOL bKeepAlive = TRUE;
  3. int nRet = setsockopt(m_socket, SOL_SOCKET, SO_KEEPALIVE,
  4. (char*)&bKeepAlive, sizeof(bKeepAlive));
  5. if (nRet == SOCKET_ERROR)
  6. {
  7. TRACE(L"setsockopt failed: %d\n", WSAGetLastError());
  8. return FALSE;
  9. }
  10. // set KeepAlive parameter
  11. tcp_keepalive alive_in;
  12. tcp_keepalive alive_out;
  13. alive_in.keepalivetime      = 500;  // 0.5s
  14. alive_in.keepaliveinterval  = 1000; //1s
  15. alive_in.onoff              = TRUE;
  16. unsigned long ulBytesReturn = 0;
  17. nRet = WSAIoctl(m_socket, SIO_KEEPALIVE_VALS, &alive_in, sizeof(alive_in),
  18. &alive_out, sizeof(alive_out), &ulBytesReturn, NULL, NULL);
  19. if (nRet == SOCKET_ERROR)
  20. {
  21. TRACE(L"WSAIoctl failed: %d\n", WSAGetLastError());
  22. return FALSE;
  23. }

其中,setsockopt设置了keepalive模式,但是系统对keepalive默认的参数可能不符合我们的要求,比如空闲2小时后才探测对端是否活跃,所以WSAIoctl函数通过tcp_keepalive结构体对这些参数进行了相应设置

tcp_keepalive这个结构体在mstcpip.h头文件中有定义:

[cpp] view plaincopy
  1. struct tcp_keepalive {
  2. ULONG onoff;   //是否开启keepalive
  3. ULONG keepalivetime;  //多长时间(ms)没有数据就开始send心跳包
  4. ULONG keepaliveinterval; //每隔多长时间(ms)send一个心跳包,
  5. //发5次(2000 XP 2003默认), 10次(Vista后系统默认)
  6. };

这个结构体设置了空闲检测时间,及检测时重复发送的间隔时间

按照msdn上的说法,这些参数也可以通过在注册表里设置,分别为:

HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\KeepAliveTime

HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\KeepAliveInterval

另外,有些人可能已经发现了,tcp_keepalive这个结构体中没有对重试次数这个参数的设置,这个参数可以通过注册表来设置,具体位置为:

HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\TcpMaxDataRetransmissions

此处的keepalivetime表示的是TCP连接处于畅通时候的探测频率,一旦探测包没有返回,就以keepaliveinterval的频率发送,经过若干次的重试,如果探测包都没有返回,那么就得出结论:TCP连接已经断开,于是上面的Recv或Send调用也就能马上返回,不会无限制地卡住了。

上图是对上面文字的说明。亮条之前,TCP处于畅通状态,KeepAlive是以1000毫秒(keepalivetime的值)的频率发送探测包,在发送到第32个探测包的时候,探测包没有返回,于是就以5000毫秒(keepalivetime的值)的频率发送探测包,重发几次后,探测包都没有返回,于是就得出结论:此TCP连接已经断开了!

设置好keepalive以后,我们通过实验来看看当client异常退出或是网络断掉的情况下,keepalive怎么通知我们异常断开的情况。这里采用select模式,实验环境为XP系统和Win7系统,几种情况返回值如下:

1. 正常断开

select函数正常返回,recv函数返回0

2. 异常断开

a)       程序异常退出,如client端重启,应用非正常关闭等

select函数正常返回,recv函数返回SOCKET_ERROR,WSAGetLastError()得到的结果为WSAECONNRESET(10054)。

b)      网络断开

结果同上:select函数正常返回,recv函数返回SOCKET_ERROR,WSAGetLastError()得到的结果为WSAECONNRESET(10054)。

对于程序异常退出的情况,实际上在不开启keepalive的情况下也是可以检测到的

tcp keepalive相关推荐

  1. 从一起丢包故障来谈谈 nginx 中的 tcp keep-alive

    一.故障 基本架构如图所示,客户端发起 http 请求给 nginx,nginx 转发请求给网关,网关再转发请求到后端微服务. 故障现象是,每隔十几分钟或者几个小时不等,客户端就会得到一个或者连续多个 ...

  2. TCP keepAlive详解(TCP心跳包)

    TCP keepAlive含义: 在TCP中有一个Keep-alive的机制可以检测死连接,原理很简单,TCP会在空闲了一定时间后发送数据给对方: 1.如果主机可达,对方就会响应ACK应答,就认为是存 ...

  3. linux tcp keepalive,[20170504]Linux TCP keepalive timers.txt

    [20170504]Linux TCP keepalive timers.txt --//上午仔细看一些文档,发现实际上netstat命令就有输出,参数--timer或者-o参数. # netstat ...

  4. golang tcp keepalive实践

    前文中已经介绍了TCP keep alive的做了详尽说明,本文结合golang,介绍如何使用TCP keep alive. 目前golang net包不提供TCP keep alive 空闲多长时间 ...

  5. TCP keepalive的详解(解惑)

    TCP是面向连接的,一般情况,两端的应用程序可以通过发送和接收数据得知对端的存活. 当两端的应用程序都没有数据发送和接收时,如何判断连接是否正常呢? 这就是SO_KEEPALIVE的作用. 1. SO ...

  6. Tcp Keepalive和HTTP Keepalive详解

    转载:https://www.cnblogs.com/hukey/p/5481173.html TCP Keepalive Tcp Keepalive的起源 双方建立交互的连接,但是并不是一直存在数据 ...

  7. php tcp keepcnt,故障处理---TCP KeepAlive

    实际生产环境中,不时会有网络连接异常中断导致应用功能异常的问题出现.这往往是因为TCP连接长期空闲,超过防火墙允许的超时时间所致,使用TCP KeepAlive是解决问题的方法之一,主要有两部分工作: ...

  8. Tcp keepalive详解

    转载:https://www.cnblogs.com/lanyangsh/p/10926806.html TCP是面向连接的,一般情况,两端的应用程序可以通过发送和接收数据得知对端的存活. 当两端的应 ...

  9. linux 防火墙 超时时间,linux – TCP Keepalive和防火墙杀死空闲会话

    在客户站点中,网络团队在客户端和服务器之间添加了防火墙.这导致空闲连接在大约40分钟的空闲时间后断开连接.网络人员说防火墙没有任何空闲连接超时,但事实是空闲连接被破坏了. 为了解决这个问题,我们首先使 ...

  10. HTTP keep-alive和TCP keepalive的区别,你了解吗?

    1.从文中找出我的IP 2.http请求中是客服端还是服务端主动关闭的tcp连接? 请阅读到最后的彩蛋部分 HTTP和TCP都是老生常谈的知识点,本文不进行铺开赘述.我们可能在HTTP和TCP中都听说 ...

最新文章

  1. Nat. Genet. | 基于遗传学主导的方法定义免疫相关性状的药物靶标
  2. php html补全,PHP实现HTML标签自动补全代码
  3. AI 玩微信跳一跳的正确姿势:跳一跳 Auto-Jump 算法详解
  4. jsp为什么不加虚拟路径都能访问_JavaWeb学习笔记一(环境配置/jsp基本介绍)
  5. 学习笔记 vs19 报错:E1696 C++ 无法打开 源 文件
  6. python切换虚拟环境和全局_为什么python虚拟环境启动后依然使用全局的python和pip...
  7. VB判断指定的WORD文档是否被打开
  8. 08.为什么要使用lombok,它解决了什么问题?
  9. 关于 pip安装的可能错误的排除
  10. 搞了一个迭代发布下SpringBoot Jar瘦身方案,老大给我打了个A+
  11. 男孩子一定要注意保护自己!
  12. CAN(FD)收发器选型及替换指南(一)
  13. 爬去当当热销图书信息
  14. 【软件工程】二、需求分析——怎么提需求?,怎么写需求?
  15. noip2016题解
  16. VS2019安装QT5.14.1全过程
  17. docker、containerd、runc、shim... 容器技术名词全解析
  18. 安卓版恶搞锁suo机生成器(百度云)
  19. php遍历数组查询数据库,php如何遍历数据库查询数组
  20. C语言学习笔记之初识

热门文章

  1. 这位教授2 年一篇 Science,再获教科书级的重大发现
  2. “你都硕士博士了,竟然还不如我!”
  3. Bash 使用技巧大补贴
  4. 199的Eagle一点都不香了!Picsee Mac图片收集整理工具是您必备
  5. 音频插件安装教程,Arturia Prophet V3 Mac安装说明
  6. 27.产品经理需要具备的数据分析能力
  7. 15产品经理要懂的-社会基本规律
  8. 苹果ios浏览器里面数字被当做电话号码
  9. C++笔记-二维棋盘数组使用BFS(宽度优先遍历)
  10. Spring Boot笔记-解决前后端分离在开发时的跨域问题