心跳包机制,是网游设计中的常用机制。从用户层面,自己发包去判断对方连线状态。可以根据情况,很灵活的使用。比如,20秒发送一个最小的数据包(也可以根据实际情况稍带一些其他数据)。如果发送没有回应,就判断对方掉线了。
二,利用tcp_keepalive机制
利用TCP的机制,通过设置系统参数,从系统层面,监测tcp的连接状态。以下为linux下的方法:
1,首先查看系统tcp_keepalive相关参数(centos和Ubuntu)
# sysctl -a|grep tcp_keepalive
显示如下:
net.ipv4.tcp_keepalive_intvl = 75
net.ipv4.tcp_keepalive_probes = 9
net.ipv4.tcp_keepalive_time = 7200
分别说一下这三个参数:
tcp_keepalive_time 参数:
是指TCP发送keepalive消息的频度,默认为7200秒,也就是两个小时。
keepalive_intvl 参数:
当探测没有确认时,重新发送探测的频度。默认是75秒。
keepalive_probes 参数:
在认定连接失效之前,发送多少个TCP的keepalive探测包。默认值是9次。
--------------------------------------------------------------------
2,修改系统的tcp_keepalive相关参数
在知道以上三个系统参数的定义和作用之后,我们来修改一下这三个参数:
修改/etc/sysctl.conf文件:
# vi /etc/sysctl.conf
在打开的文件中,加入如下三行:
net.ipv4.tcp_keepalive_intvl = 1
net.ipv4.tcp_keepalive_probes = 1
net.ipv4.tcp_keepalive_time = 5
保存文件。
--------------------------------------------------------------------
3,重启服务器。
# reboot
附注:或者临时使系统设置生效也行:# sysctl -p
--------------------------------------------------------------------
4,修改程序代码部分。
注意:仅仅配置内核参数是不够的,还必须在编程的时候设置套接字的选项,调用函数是
socket.setsockopt(level, optname, value)
示例:
level为SOL_SOCKET的话,选项为SO_KEEPALIVE,值为布尔。
socket.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, True)
此外还可以设置TCP选项(设置的level为SOL_TCP而不是SOL_SOCKET)覆盖系统全局设置
TCP_KEEPCNT 与tcp_keepalive_probes 对应
TCP_KEEPIDLE 与tcp_keepalive_time 对应
TCP_KEEPINTVL 与tcp_keepalive_intvl 对应
为什么要心跳检查?
因为目前讨论的数据连接场景,都是无源连接,排除NAT的情况,连接就是存在于src和dest两端OS中的状态机,为什么会要用无源连接呢,有源是连接建立带宽就分配好了,不传有效数据这个带宽也被占用着,这不就浪费了,虚拟信号时代的电话就是有源的。
心跳检查是两端都要做的,不做的那一端一样存在状态不对而不自知的情况。
状态机在两端是有可能不一致的,比如一端认为这条连接已经销毁,另外一端可能认为仍有效。心跳机制的作用之一就是解决这种不一致的情况,类似“校对”的作用。
在浏览器上请求一个需要长时间才得到结果的请求,最后返回超时错误。
你说的情况我们经常遇到,我估计你说的就是客户端自己的超时设置,也就是如果http响应无法在限定时间内完成(比如1秒内),那么客户端应用程序自己会报timeout错误。
这应该不是中间设备做了reset,因为如果是那样,这个中间设备应该会给客户端和服务端都发TCP RST,然后客户端报错会变成ECONNRESET这种(ECONNRESET是linux的网络协议栈报给用户空间程序的报错)。
心跳消息显示push ack是为何呢?
按照TCP协议(参考RFC793)规定, *** 作系统收到有PSH标志位的报文后,这些报文不会被驻留在接收缓冲区,而是要立即通知用户空间程序来接收。这样对于用户空间程序及时收发处理心跳报文是有利的。
AWS的nlb keep-alive最大是350s,我们的服务端keep-alive是默认配置,客户端使用了连接池,也进行了探测,但是有个骚 *** 作是随机选取池子里面的一个链接进行探测,然后那些超过350s还没探测的链接,再次使用就出问题了。
你说的“随机选取池子里面的一个链接进行探测”,我判断是健康检查,就是业务健康性(类似k8s的readiness probe),而不是keepalive。
如果是这样的话,这个健康检查确实不是为保活而生的,也很难达到保活的目的。建议这样做设置:client idle timeout <LB idle timeout <server idle timeout,这样可以尽可能的保证不出现连接失效的情况。
这里说的“保活时间”,不是心跳包的间隔,而是空闲保活时间,idle timeout。
保活机制:心跳包异常导致应用重启?
https://time.geekbang.org/column/article/482610
如何解决 Keep-Alive 导致 ECONNRESET 的问题
https://zhuanlan.zhihu.com/p/86953757
解决使用 KeepAlive Agent 遇到的 ECONNRESET
https://zhuanlan.zhihu.com/p/34147188
收到心跳报文,更新你客户端链表中的m_time/* 例如10妙发送一次 */
用户->m_time = (time_t)time(NULL)// time_t m_time
用一个独立线程检测是否超时
while (1) {
sleep(你定时检测心跳的时间)
time_t local_time = (time_t)time(NULL)
/*遍历你的现有用户*/
/* 例如 你的超时时间为40,那么就是你至少4次没收到心跳更新可以肯定需要断开连接了*/
if (( local_time - 用户->m_time) > 超时时间){
close (用户->sockfd)
}
}
还有疑问么?
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)