网络编程实战
盛延敏
前大众点评云平台首席架构师
44207 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 40 讲
网络编程实战
15
15
1.0x
00:00/00:00
登录|注册

12 | 连接无效:使用Keep-Alive还是应用心跳来检测?

设计PING-PONG协议
使用定时器
关键点
时间间隔不可接受
对端程序崩溃或报文不可达
对端程序崩溃并重启
对端程序正常工作
保活探测次数
保活时间间隔
保活时间
无活动时发送探测报文
定义时间段
消息订阅者未及时检测连接有效性
原因:NATS服务器崩溃导致连接中断
连接显示正常但实际无效
客户端认为连接正常
客户端判断连接无效
处理心跳报文
监听过程建立
处理心跳报文
select定时器准备
套接字创建和连接建立
消息类型
定义消息对象结构体
设计PING-PONG机制
TCP自身的keep-Alive机制
开启TCP保活需考虑情况
可定义变量
原理
故障根本原因
故障排查
消息投递和订阅处理
多次探活决定TCP连接是否死亡的原因
额外探活报文对带宽的影响
TCP探活方法是否适用于UDP
依赖系统定时器和应用层报文协议
可在应用程序里建立保持Keep Alive的机制
TCP没有系统的保活能力
服务器端休眠时间为5秒
服务器端休眠时间为60秒
服务器端程序设计
客户端程序设计
消息格式设计
保持活跃机制
NATS消息系统
思考题
总结
实验
应用层探活
TCP Keep-Alive选项
从一个例子开始
连接无效:使用Keep-Alive还是应用心跳来检测?

该思维导图由 AI 生成,仅供参考

你好,我是盛延敏,这里是网络编程实战第 12 讲,欢迎回来。
上一篇文章中,我们讲到了如何使用 close 和 shutdown 来完成连接的关闭,在大多数情况下,我们会优选 shutdown 来完成对连接一个方向的关闭,待对端处理完之后,再完成另外一个方向的关闭。
在很多情况下,连接的一端需要一直感知连接的状态,如果连接无效了,应用程序可能需要报错,或者重新发起连接等。
在这一篇文章中,我将带你体验一下对连接状态的检测,并提供检测连接状态的最佳实践。

从一个例子开始

让我们用一个例子开始今天的话题。
我之前做过一个基于 NATS 消息系统的项目,多个消息的提供者 (pub)和订阅者(sub)都连到 NATS 消息系统,通过这个系统来完成消息的投递和订阅处理。
突然有一天,线上报了一个故障,一个流程不能正常处理。经排查,发现消息正确地投递到了 NATS 服务端,但是消息订阅者没有收到该消息,也没能做出处理,导致流程没能进行下去。
通过观察消息订阅者后发现,消息订阅者到 NATS 服务端的连接虽然显示是“正常”的,但实际上,这个连接已经是无效的了。为什么呢?这是因为 NATS 服务器崩溃过,NATS 服务器和消息订阅者之间的连接中断 FIN 包,由于异常情况,没能够正常到达消息订阅者,这样造成的结果就是消息订阅者一直维护着一个“过时的”连接,不会收到 NATS 服务器发送来的消息。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文介绍了在网络编程中如何检测连接状态的最佳实践。作者首先通过一个基于NATS消息系统的故障案例引出了连接状态检测的重要性。接着详细介绍了TCP的Keep-Alive机制,包括其原理和在Linux系统中的相关设置。作者指出了TCP保活机制的局限性,提出了在应用层实现连接探活的解决方案。最后,作者介绍了在应用层设计PING-PONG协议的关键点,并给出了消息格式设计的示例。通过本文,读者可以了解到TCP保活机制的原理和局限性,以及在应用层实现连接探活的方法,为网络编程中连接状态的检测提供了有益的参考。 文章通过客户端和服务器端程序设计,演示了如何利用select函数和心跳包实现TCP连接的保活机制。通过实验,展示了不同休眠时间对连接状态的影响,以及如何通过多次探活来判断TCP连接是否已经死亡。总结指出,虽然TCP没有提供系统的保活能力,但可以在应用程序里建立这种机制,依赖于系统定时器和恰当的应用层报文协议,比如心跳包。最后,作者留下了两个思考题,引发读者对TCP探活方法适用性和额外探活报文对带宽的影响进行思考。 通过本文,读者可以快速了解TCP连接状态检测的重要性、TCP保活机制的实现方法以及对带宽的影响,为网络编程中连接状态的监测提供了有益的技术参考。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《网络编程实战》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(46)

  • 最新
  • 精选
  • 传说中的成大大
    置顶
    思考题 1. udp不需要连接 所以没有必要心跳包 2. 我觉得还是很有必要判定存活 像以前网吧打游戏 朋友的电脑突然蓝屏死机 朋友的角色还残留于游戏中,所以服务器为了判定他是否真的存活还是需要一个心跳包 隔了一段时间过后把朋友角色踢下线

    作者回复: 2是一个很好的例子。

    2019-08-28
    5
    20
  • fjpcode
    1.UDP里面各方并不会维护一个socket上下文状态是无连接的,如果为了连接而保活是不必要的,如果为了探测对端是否正常工作而做ping-pong也是可行的。 2.额外的探活报文是会占用一些带宽资源,可根据实际业务场景,适当增加保活时间,降低探活频率,简化ping-pong协议。 3.多次探活是为了防止误伤,避免ping包在网络中丢失掉了,而误认为对端死亡。

    作者回复: 👍

    2019-08-28
    2
    49
  • 扩散性百万咸面包
    想到HTTP Header也能设置Connection: Keep-Alive,也是应用层协议,是不是底层实现也类似于定时器+Ping Pong的思路?

    作者回复: HTTP的 keep-alive是为了使http变成长连接,在此前的http 1.0中,每次http的请求-响应之后,tcp连接就会被释放掉,这显然是非常浪费的,于是通过加入keep-alive,使得http连接不会被立即释放。

    2020-04-17
    2
    19
  • 满怀
    老师 我想问一下 看您在回复当中有说 虽然TCP本身的keep-alive机制可以设置保活时间,保活探测时间间隔以及探测次数,但是应用层会无法感知,那么这种情况下会怎么处理呢 就是文中所给出的三种情况吗

    作者回复: 是的,大部分的应用程序开发者都会选择自己在应用层处理连接有效性的检测。

    2019-12-20
    8
  • 蛮野
    文章中提到保活有两个方向,实际应用中,会有两个方向同时探测的场景吗

    作者回复: 当然有。服务器端要探活client来保证自己不会维护无效连接,客户端来探活保持自己是不是可以持续申请资源。

    2019-12-17
    8
  • 徐凯
    老师 同步连接可以实现心跳包么 如果不能的话 那同步连接如果因为客户端崩溃 没有通过四次挥手结束连接 服务端还堵塞在接收数据 那么这样如何判断对方已经离开呢

    作者回复: 首先,客户端应用程序崩溃是可以有FIN包的,如果有的话,read阻塞就可以返回了;其次,如果真的是客户端机器跪了,那么是没有FIN包发出的,这个时候,我们只好一直在那里傻等。 且慢,还有别的辙,那就是不要用阻塞I/O,不要在哪里傻傻等待。使用I/O复用就可以办到的,往后看就会明白了。

    2019-09-06
    3
    6
  • 石将从
    为啥这句套接字要加1呢?int rc = select(socket_fd + 1, &readmask, NULL, NULL, &tv);

    作者回复: 这是因为,嗯,跟select实现有关,我再后面讲select时详细剖析,现在先记住吧。

    2019-08-29
    4
    5
  • rongyefeng
    服务器端恢复心跳包这段 case MSG_PING: { messageObject pong_message; pong_message.type = MSG_PONG; sleep(sleepingTime); ssize_t rc = send(connfd, (char *) &pong_message, sizeof(pong_message), 0); 老师,这个type是int类型,应该将其转为网络序才对吧? pong_message.type = htonl(MSG_PONG); 而且你的客户端程序也是有转换的,是不是服务器端这里忘记了?

    作者回复: Bingo。确实是我忘记了:)

    2020-05-18
    4
  • HunterYuan
    对于协议栈中的TCP的keep-alive是可以手动配置的,全局配置通过修改net.ipv4下的等参数;局部配置可以通过setsockopt修改socket选项。在工作中遇到过一个oracle,windows服务器的保活时间大于,我们设备状态连接表的保活时间,导致,一段时间后重连,导致服务器报错问题。当时最最快的处理办法是,修改window默认的保活时间小于状态连接失效时间。

    作者回复: 学习了。

    2019-12-17
    4
  • LDxy
    TCP本身的keep-alive的时间是可以自己设置的吗?如果是可以自己设置的,为何还需要自己实现这个机制?

    作者回复: 可以设置的,但是有时候应用层需要感知处理这样的异常

    2019-08-28
    4
收起评论
显示
设置
留言
46
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部