TCP KeepAlive 机制详解

腾讯公司标志配图

TCP Keep-Alive 的原理

一个 TCP 连接上,如果通信双方都不向对方发送数据,那么 TCP 连接就不会有任何数据交换。

假设应用程序是一个 web 服务器,客户端发出三次握手(关于握手与挥手的详细过程,可以参看本站的《三次握手与四次挥手》)以后故障宕机或被踢掉网线,对于 web 服务器而言,下一个数据包将永远无法到来,但是它一无所知。TCP Keep-Alive 机制就是为了解决这个问题。顺带一提,拔掉网线的瞬间连接并不会立即断开,具体原因可以看本站的《拔掉网线后,TCP 连接还在吗》。

TCP Keep-Alive 机制就是一种确保 TCP 连接有效性的方法,主要用于检测长时间没有数据交换的连接是否仍然存活。

它的作用就是探测对端的连接有没有失效:通过定时发送探测包来探测连接的对端是否存活。不过默认情况下需要 7200s 没有数据包交互才会发送 keepalive 探测包,往往这个时间太久了,我们熟知的很多组件都没有开启 keepalive 特性,而是选择在应用层做心跳机制。

一般情况下,做服务器开发,都会在应用层自己做心跳机制。例如一个心跳包结构体:

enum MsgType{
    HEARTBEAT = 10,
    LOGIN = 11,
    LOGOUT = 12,
    ...
};

struct MyHeader{
    MyHeader()
    {
        memset(this, 0, sizeof(*this));
        usLen = sizeof(*this);
    }
    uint16_t usLen;
    int cType;
};

struct MyMsgHeart : public MyHeader{
    MyMsgHeart()
    {
        memset(this, 0, sizeof(MyMsgHeart));
        usLen = sizeof(MyMsgHeart);
        cType = HEARTBEAT;
    }
};

TCP Keep-Alive 系统内核参数

查询命令如下:

sysctl -a | grep keepalive

三个参数的含义如下:

net.ipv4.tcp_keepalive_intvl = 75    //没有接收到对方确认,继续发送保活探测包的发送频率,默认值为75s
net.ipv4.tcp_keepalive_probes = 9    //没有接收到对方确认,继续发送保活探测包次数
net.ipv4.tcp_keepalive_time = 7200   //在TCP保活打开的情况下,最后一次数据交换到TCP发送第一个保活探测包的间隔,即允许的持续空闲时长,或者说每次正常发送心跳的周期,默认值为7200s(2h)

TCP Keep-Alive 不是默认启用的,需要在创建套接字时显式设置,通常是通过套接字选项 SO_KEEPALIVE 来开启。

C/C++ 中,通过 setsockopt 设置 keepalive 开关(默认 socket 是关闭 keepalive 的):

int optval = 1;
::setsockopt(hSocket, IPPROTO_TCP, TCP_NODELAY,
    &optval, static_cast<socklen_t>(sizeof optval));
::setsockopt(hSocket, SOL_SOCKET, SO_REUSEADDR,
    &optval, static_cast<socklen_t>(sizeof optval));
::setsockopt(hSocket, SOL_SOCKET, SO_KEEPALIVE,
    &optval, static_cast<socklen_t>(sizeof optval));  //这里打开Keep-Alive

注意这里只是打开了 SO_KEEPALIVE 开关,探测的节奏并不会随之改变:不做额外设置的话,内核就按上面三个参数的默认值来工作——7200s 空闲后开始探测,每 75s 一次,共 9 次。示例里顺带设置的 TCP_NODELAY、SO_REUSEADDR 与保活无关。如果想在套接字级别自定义探测节奏,可以用 TCP_KEEPIDLE、TCP_KEEPINTVL、TCP_KEEPCNT 这三个选项(IPPROTO_TCP 层级)分别覆盖空闲时长、探测间隔和探测次数。


   转载规则


《TCP KeepAlive 机制详解》 由 吴杭沉 采用 知识共享署名 4.0 国际许可协议 进行许可。
 上一篇
TCP 三次握手与四次挥手 TCP 三次握手与四次挥手
不管面试 Java、C/C++、Python 等开发岗位,TCP 的知识点可以说是必问的了。 任 TCP 虐我千百遍,我仍待 TCP 如初恋。 遥想小林当年校招时常因 TCP 面试题被刷,真是又爱又恨…… 过去不会没关系,今天就让我们来消除
2021-08-31
下一篇 
TCP 的那些事儿:协议头部与可靠传输 TCP 的那些事儿:协议头部与可靠传输
TCP 是一个巨复杂的协议,因为它要解决很多问题,而这些问题又带出了很多子问题和阴暗面。所以学习 TCP 本身是个比较痛苦的过程,但对于学习的过程却能让人有很多收获。关于 TCP 这个协议的细节,我还是推荐你去看 W. Richard S
2021-08-17
  目录