[关闭]
@lzb1096101803 2016-03-14T07:57:22.000000Z 字数 2277 阅读 757

TCP保活

电话面试


为什么需要保活

http://www.nowamagic.net/academy/detail/23350382
http://www.tldp.org/HOWTO/html_single/TCP-Keepalive-HOWTO/#whatis
1. 检查死去的连接

  1. _____ _____
  2. | | | |
  3. | A | | B |
  4. |_____| |_____|
  5. ^ ^
  6. |--->--->--->-------------- SYN -------------->--->--->---|
  7. |---<---<---<------------ SYN/ACK ------------<---<---<---|
  8. |--->--->--->-------------- ACK -------------->--->--->---|
  9. | |
  10. | system crash ---> X
  11. |
  12. | system restart ---> ^
  13. | |
  14. |--->--->--->-------------- PSH -------------->--->--->---|
  15. |---<---<---<-------------- RST --------------<---<---<---|
  16. | |
  1. 阻止因网络连接不活跃(长时间没有数据包)而导致的连接中断
    说的是,很多网络设备,尤其是NAT路由器,由于其硬件的限制(例如内存、CPU处理能力),无法保持其上的所有连接,因此在必要的时候,会在连接池中选择一些不活跃的连接踢掉。典型做法是LRU,把最久没有数据的连接给T掉。通过使用TCP的KeepAlive机制(修改那个time参数),可以让连接每隔一小段时间就产生一些ack包,以降低被T掉的风险,当然,这样的代价是额外的网络和CPU负担。
  1. _____ _____ _____
  2. | | | | | |
  3. | A | | NAT | | B |
  4. |_____| |_____| |_____|
  5. ^ ^ ^
  6. |--->--->--->---|----------- SYN ------------->--->--->---|
  7. |---<---<---<---|--------- SYN/ACK -----------<---<---<---|
  8. |--->--->--->---|----------- ACK ------------->--->--->---|
  9. | | |
  10. | | <--- connection deleted from table |
  11. | | |
  12. |--->- PSH ->---| <--- invalid connection |
  13. | | |

PSH:收到一个数据后,马上送往应用进程
RST:表示复位,用来异常的关闭连接,在TCP的设计中它是不可或缺的。发送RST包关闭连接时,不必等缓冲区的包都发出去,直接就丢弃缓存区的包发送RST包。而接收端收到RST包后,也不必发送ACK包来确认。

  1. 1 端口未打开
  2. 2 请求超时
  3. 3 提前关闭
  4. 4 在一个已关闭的socket上收到数据

如何保活

很多应用层协议都有HeartBeat机制,通常是客户端每隔一小段时间向服务器发送一个数据包,通知服务器自己仍然在线,并传输一些可能必要的数据。使用心跳包的典型协议是IM,比如QQ/MSN/飞信等协议。

心跳包之所以叫心跳包是因为:它像心跳一样每隔固定时间发一次,以此来告诉服务器,这个客户端还活着。事实上这是为了保持长连接,至于这个包的内容,是没有什么特别规定的,不过一般都是很小的包,或者只包含包头的一个空包。

在TCP的机制里面,本身是存在有心跳包的机制的,也就是TCP的选项:SO_KEEPALIVE。系统默认是设置的2小时的心跳频率。但是它检查不到机器断电、网线拔出、防火墙这些断线。而且逻辑层处理断线可能也不是那么好处理。一般,如果只是用于保活还是可以的。

TCP协议的KeepAlive机制

学过TCP/IP的同学应该都知道,传输层的两个主要协议是UDP和TCP,其中UDP是无连接的、面向packet的,而TCP协议是有连接、面向流的协议。

所以非常容易理解,使用UDP协议的客户端(例如早期的“OICQ”,听说OICQ.com这两天被抢注了来着,好古老的回忆)需要定时向服务器发送心跳包,告诉服务器自己在线。

然而,MSN和现在的QQ往往使用的是TCP连接了,尽管TCP/IP底层提供了可选的KeepAlive(ACK-ACK包)机制,但是它们也还是实现了更高层的心跳包。似乎既浪费流量又浪费CPU,有点莫名其妙。

具体查了下,TCP的KeepAlive机制是这样的,首先它貌似默认是不打开的,要用setsockopt将SOL_SOCKET.SO_KEEPALIVE设置为1才是打开,并且可以设置三个参数tcp_keepalive_time/tcp_keepalive_probes/tcp_keepalive_intvl,分别表示连接闲置多久开始发keepalive的ack包、发几个ack包不回复才当对方死了、两个ack包之间间隔多长,在我测试的Ubuntu Server 10.04下面默认值是7200秒(2个小时,要不要这么蛋疼啊!)、9次、75秒。于是连接就了有一个超时时间窗口,如果连接之间没有通信,这个时间窗口会逐渐减小,当它减小到零的时候,TCP协议会向对方发一个带有ACK标志的空数据包(KeepAlive探针),对方在收到ACK包以后,如果连接一切正常,应该回复一个ACK;如果连接出现错误了(例如对方重启了,连接状态丢失),则应当回复一个RST;如果对方没有回复,服务器每隔intvl的时间再发ACK,如果连续probes个包都被无视了,说明连接被断开了。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注