欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

理解心跳包的作用:检测网络连接是否中断

最编程 2024-08-09 07:09:18
...

在维持一个tcp长连接的过程中,我们一般都需要在客户端代码这里写一个心跳包向服务端发送。但为什么要写这个,它的意义是什么?
意义在于有了心跳包就可以做到让服务端/客户端做到断线感知。

我们的客户端一般位于内网,内网机器如果不主动向外发起连接,外网机没法直接连内网,这也是内网机安全的原因之一,又因为路由器会把内网发起的连接记录起来,但是过一段时间可能会记录丢失,所以客户端每隔一段时间都会向服务器发送消息,以保证服务器随时可以找到你,这个东西称为心跳包。

理论上来说,每一个连接都会保持连接的,但实际情况是,如果中间节点出现故障是难以知道的 ,更要命的是有的节点(防火墙)会自动把一定时间内没有数据交互的连接给断掉,在这个时候就需要我们的心跳包来维持一直跟服务器有数据交互,在获知断线以后,服务器逻辑可能需要做一些事情,比如断线之后的数据清理与重新连接,总之心跳是用来维持长连接的保活与断线处理。

如果不主动关闭Socket的话,系统是不会自动关闭的,除非当前的进程已经挂掉了,操作系统把占用的Socket回收了才会关闭,为什么需要心跳包来判断当前连接是否有效可被使用的。在实际操作中,假设一段时间没有数据传输,理论上长连接应该是存活的,但是网路复杂中途出现的问题也会比较常见,譬如网线被掐断,对象进程被杀掉,频繁丢包(即在没有完成挥手动作即断线),对方这时候的TCP长连接是不可使用的,但是对于应用层并不知道。如果需要知道当前的网络状况则需要很复杂的超时进行了解,TCP底层就实现了这样的功能,心跳机制是TCP在一段时间间隔后发送确定连接是否存在,如果确定存在的话,就会回传一个包来确定连接是存在的,如果没有返回包的话,则应该通知上层,网络出现了问题,需要进行连接失败的操作了

所以,即便客户端是采用死循环的方式连接到服务器,对于特定的服务端与客户端来说也需要一定时间间隔的心跳,告诉服务器我还活着,虽然我没干活,也没说话,但是别把我给关了。

总结

简而言之,如果客户端没有执行socket.close方法的情况下,出现了连接断开(这个断开可能是各种各样的原因,网线被掐断是物理原因,对象进程被杀死在服务端和客户端都可能出现,中间路由异常都会引起问题),如果这个时候客户端和服务端之间没有做数据交互,那么服务端和客户端都认为socket并没有关闭,依然维持着这种假死状态。
既然这个,我们就启用心跳包就好了,我们不会允许客户端服务端在长连接状态下长时间没有数据交互。我们会在没有数据交互的状态下,定时发送一条数据,这样就可以感知到连接是否在线。

ps:在网络编程中,可以设置一个参数叫keep_alive这个和心跳包的逻辑是相同的,只不过一般来说,它的心跳周期太长了,一般是两个小时发送一次心跳(空报文),黄瓜菜都凉了。优点是我们不需要自己写心跳了。

什么是keep_alive
链接建立之后,如果应用程序或者上层协议一直不发送数据,或者隔很长时间才发送一次数据,当链接很久没有数据报文传输时如何去确定对方还在线,到底是掉线了还是确实没有数据传输,链接还需不需要保持,这种情况在TCP协议设计中是需要考虑到的。
TCP协议通过一种巧妙的方式去解决这个问题,当超过一段时间之后,TCP自动发送一个数据为空的报文给对方,如果对方回应了这个报文,说明对方还在线,链接可以继续保持,如果对方没有报文返回,并且重试了多次之后则认为链接丢失,没有必要保持链接。

关于java中的keepalive可以看这一篇:https://www.cnblogs.com/xiao-tao/p/9718017.html

推荐阅读