今天去hj面试,面试官问了一个网络方面的问题,TCP有心跳包功能,为什么我们一般在写程序时还要在应用层加心跳功能?
以前我写的通信程序,都在应用层加了心跳功能,虽然TCP是可靠传输,某一端断开连接的话,是会通知到另一端的,但对于断电、拔网线、路由器故障这种突发情况,就无法通知到网络上的另一端了,所以需要心跳功能隔一段时间来帮我们检测当前连接是否可用。
之前接触别人和自己写的代码都在应用层实现了心跳功能,就一直以为传输层本身是没有心跳功能的,所以还跟面试官争了半天传输层是没有心跳功能的,回来查了下资料,原来TCP是有KeeAlive机制的,想想真是太丢人了。
在TCP协议里,本身的心跳包机制SO_KEEPALIVE,系统默认设置的是7200秒的启动时间。默认是关闭的,需要用setsocketopt将SOL_SOCKET.SO_KEEPALIVE设置为1打开,有三个参数可以设置,tcp_keepalive_time、tcp_keepalive_probes、tcp_keepalive_intvl,分别表示连接闲置多久才开始发心跳包、连发几次心跳包没有回应表示连接已断开、心跳包之间间隔时间。
这里有一篇非常详细介绍TCP Keepalive的文章: http://tldp.org/HOWTO/html_single/TCP-Keepalive-HOWTO,2.2节提到
Why use TCPkeepalive?
1.Checking for dead peers(断线检测)
2.Preventing disconnection due to network inactivity(保活)
心跳包的作用:
1.保活
在传输的链路上,有的节点(防火墙、NAT)会自动把一定时间内没有数据交互的连接给断掉,这个时候就需要我们定时发送心跳包,让这些节点知道这条连接仍在使用中,维持长连接,保活。
2.断线处理
通过心跳包获知连接断开后,启动相应的处理机制,如重新连接、断线后的数据清理等。
对之前面试官提的问题:“既然TCP已有心跳机制,为什么我们还要在应用层实现自己的心跳功能呢?”,现在我想有这么几点理由:
1.TCP心跳机制是传输层实现的,只要当前连接是可用的,对端就会ACK我们的心跳,而对于当前对端应用是否能正常提供服务,TCP层的心跳机制是无法获知的。我们在应用层实现的心跳功能是依赖于对端应用的,如果对端当前无法正常提供服务,通过应用层心跳功能马上就可以获知,我们可以进行相应的处理;
2.tcp_keepalive_time参数的设置是秒级,对于极端情况,我们可能想在毫秒级就检测到连接的状态,这个TCP心跳机制就无法办到;
3.通用性,应用层心跳功能不依赖于传输层协议,如果有一天我们想将传输层协议由TCP改为UDP,那么传输层不提供心跳机制了,应用层的心跳是通用的,此时或许只用修改少量地方代码即可;
4.有些运营商会过滤掉keep包;
应用层心跳包不好的地方
增加开发工作量,由于应用特定的网络框架,还可能增加代码结构的复杂度,再就是根据上面的推测,应用层心跳的流量消耗还是更大的,毕竟这本质上还是个普通的数据包。