tcp keepalive
部分信息可以看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大致的原理,下来看看在程序中怎么用,怎么设置参数:
- #include <mstcpip.h>
- BOOL bKeepAlive = TRUE;
- int nRet = setsockopt(m_socket, SOL_SOCKET, SO_KEEPALIVE,
- (char*)&bKeepAlive, sizeof(bKeepAlive));
- if (nRet == SOCKET_ERROR)
- {
- TRACE(L"setsockopt failed: %d\n", WSAGetLastError());
- return FALSE;
- }
- // set KeepAlive parameter
- tcp_keepalive alive_in;
- tcp_keepalive alive_out;
- alive_in.keepalivetime = 500; // 0.5s
- alive_in.keepaliveinterval = 1000; //1s
- alive_in.onoff = TRUE;
- unsigned long ulBytesReturn = 0;
- nRet = WSAIoctl(m_socket, SIO_KEEPALIVE_VALS, &alive_in, sizeof(alive_in),
- &alive_out, sizeof(alive_out), &ulBytesReturn, NULL, NULL);
- if (nRet == SOCKET_ERROR)
- {
- TRACE(L"WSAIoctl failed: %d\n", WSAGetLastError());
- return FALSE;
- }
其中,setsockopt设置了keepalive模式,但是系统对keepalive默认的参数可能不符合我们的要求,比如空闲2小时后才探测对端是否活跃,所以WSAIoctl函数通过tcp_keepalive结构体对这些参数进行了相应设置
tcp_keepalive这个结构体在mstcpip.h头文件中有定义:
- struct tcp_keepalive {
- ULONG onoff; //是否开启keepalive
- ULONG keepalivetime; //多长时间(ms)没有数据就开始send心跳包
- ULONG keepaliveinterval; //每隔多长时间(ms)send一个心跳包,
- //发5次(2000 XP 2003默认), 10次(Vista后系统默认)
- };
这个结构体设置了空闲检测时间,及检测时重复发送的间隔时间
按照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相关推荐
- 从一起丢包故障来谈谈 nginx 中的 tcp keep-alive
一.故障 基本架构如图所示,客户端发起 http 请求给 nginx,nginx 转发请求给网关,网关再转发请求到后端微服务. 故障现象是,每隔十几分钟或者几个小时不等,客户端就会得到一个或者连续多个 ...
- TCP keepAlive详解(TCP心跳包)
TCP keepAlive含义: 在TCP中有一个Keep-alive的机制可以检测死连接,原理很简单,TCP会在空闲了一定时间后发送数据给对方: 1.如果主机可达,对方就会响应ACK应答,就认为是存 ...
- linux tcp keepalive,[20170504]Linux TCP keepalive timers.txt
[20170504]Linux TCP keepalive timers.txt --//上午仔细看一些文档,发现实际上netstat命令就有输出,参数--timer或者-o参数. # netstat ...
- golang tcp keepalive实践
前文中已经介绍了TCP keep alive的做了详尽说明,本文结合golang,介绍如何使用TCP keep alive. 目前golang net包不提供TCP keep alive 空闲多长时间 ...
- TCP keepalive的详解(解惑)
TCP是面向连接的,一般情况,两端的应用程序可以通过发送和接收数据得知对端的存活. 当两端的应用程序都没有数据发送和接收时,如何判断连接是否正常呢? 这就是SO_KEEPALIVE的作用. 1. SO ...
- Tcp Keepalive和HTTP Keepalive详解
转载:https://www.cnblogs.com/hukey/p/5481173.html TCP Keepalive Tcp Keepalive的起源 双方建立交互的连接,但是并不是一直存在数据 ...
- php tcp keepcnt,故障处理---TCP KeepAlive
实际生产环境中,不时会有网络连接异常中断导致应用功能异常的问题出现.这往往是因为TCP连接长期空闲,超过防火墙允许的超时时间所致,使用TCP KeepAlive是解决问题的方法之一,主要有两部分工作: ...
- Tcp keepalive详解
转载:https://www.cnblogs.com/lanyangsh/p/10926806.html TCP是面向连接的,一般情况,两端的应用程序可以通过发送和接收数据得知对端的存活. 当两端的应 ...
- linux 防火墙 超时时间,linux – TCP Keepalive和防火墙杀死空闲会话
在客户站点中,网络团队在客户端和服务器之间添加了防火墙.这导致空闲连接在大约40分钟的空闲时间后断开连接.网络人员说防火墙没有任何空闲连接超时,但事实是空闲连接被破坏了. 为了解决这个问题,我们首先使 ...
- HTTP keep-alive和TCP keepalive的区别,你了解吗?
1.从文中找出我的IP 2.http请求中是客服端还是服务端主动关闭的tcp连接? 请阅读到最后的彩蛋部分 HTTP和TCP都是老生常谈的知识点,本文不进行铺开赘述.我们可能在HTTP和TCP中都听说 ...
最新文章
- Nat. Genet. | 基于遗传学主导的方法定义免疫相关性状的药物靶标
- php html补全,PHP实现HTML标签自动补全代码
- AI 玩微信跳一跳的正确姿势:跳一跳 Auto-Jump 算法详解
- jsp为什么不加虚拟路径都能访问_JavaWeb学习笔记一(环境配置/jsp基本介绍)
- 学习笔记 vs19 报错:E1696 C++ 无法打开 源 文件
- python切换虚拟环境和全局_为什么python虚拟环境启动后依然使用全局的python和pip...
- VB判断指定的WORD文档是否被打开
- 08.为什么要使用lombok,它解决了什么问题?
- 关于 pip安装的可能错误的排除
- 搞了一个迭代发布下SpringBoot Jar瘦身方案,老大给我打了个A+
- 男孩子一定要注意保护自己!
- CAN(FD)收发器选型及替换指南(一)
- 爬去当当热销图书信息
- 【软件工程】二、需求分析——怎么提需求?,怎么写需求?
- noip2016题解
- VS2019安装QT5.14.1全过程
- docker、containerd、runc、shim... 容器技术名词全解析
- 安卓版恶搞锁suo机生成器(百度云)
- php遍历数组查询数据库,php如何遍历数据库查询数组
- C语言学习笔记之初识