TCP是面向连接的,一般情况,两端的应用程序可以通过发送和接收数据得知对端的存活。

当两端的应用程序都没有数据发送和接收时,如何判断连接是否正常呢?

这就是SO_KEEPALIVE的作用。

1. SO_KEEPALIVE 的作用

1.1 SO_KEEPALIVE的定义

SO_KEEPALIVE用于开启或者关闭保活探测,默认情况下是关闭的。

SO_KEEPALIVE开启时,可以保持连接检测对方主机是否崩溃,避免(服务器)永远阻塞于TCP连接的输入。

相关的属性包括:

tcp_keepalive_timetcp_keepalive_probestcp_keepalive_intvl

tcp_keepalive_intvl (integer; default: 75; since Linux 2.4)
The number of seconds between TCP keep-alive probes. tcp_keepalive_probes (integer; default: 9; since Linux 2.2)
The maximum number of TCP keep-alive probes to send before
giving up and killing the connection if no response is
obtained from the other end. tcp_keepalive_time (integer; default: 7200; since Linux 2.2)
The number of seconds a connection needs to be idle before TCP
begins sending out keep-alive probes. Keep-alives are sent
only when the SO_KEEPALIVE socket option is enabled. The
default value is 7200 seconds (2 hours). An idle connection
is terminated after approximately an additional 11 minutes (9
probes an interval of 75 seconds apart) when keep-alive is
enabled. Note that underlying connection tracking mechanisms and
application timeouts may be much shorter.

这些属性可以在/proc/sys/net/ipv4/下查看:

cat /proc/sys/net/ipv4/tcp_keepalive_time
7200 cat /proc/sys/net/ipv4/tcp_keepalive_probes
9 cat /proc/sys/net/ipv4/tcp_keepalive_intvl
75

也可以通过命令行查看:

sudo sysctl -a | grep keepalive

net.ipv4.tcp_keepalive_time = 7200
net.ipv4.tcp_keepalive_probes = 9
net.ipv4.tcp_keepalive_intvl = 75

1.2 连接探活的过程

开启SO_KEEPALIVE后,如果2小时内在此套接口的任一方向都没有数据交换,TCP就自动给对方发一个保持存活探测分节(keepalive probe)。这是一个对方必须响应的TCP分节.

它会导致以下三种情况:

  • 对方接收一切正常:以期望的ACK响应。2小时后,TCP将发出另一个探测分节。
  • 对方已崩溃且已重新启动:以RST响应。套接口的待处理错误被置为ECONNRESET,套接 口本身则被关闭。
  • 对方无任何响应:源自berkeley的TCP发送另外8个探测分节,相隔75秒一个,试图得到一个响应。一共尝试9次,即在发出第一个探测分节11分钟 15秒后若仍无响应就放弃。套接口的待处理错误被置为ETIMEOUT,套接口本身则被关闭。如ICMP错误是“host unreachable(主机不可达)”,说明对方主机并没有崩溃,但是不可达,这种情况下待处理错误被置为 EHOSTUNREACH。

根据上面的介绍我们可以知道对端以一种非优雅的方式断开连接的时候,我们可以设置SO_KEEPALIVE属性使得我们在2小时以后发现对方的TCP连接是否依然存在。

int keepAlive = 1;

setsockopt(listenfd, SOL_SOCKET, SO_KEEPALIVE, (void*)&keepAlive, sizeof(keepAlive));

如果我们不能接受如此之长的等待时间,怎么办?

2.设置TCP KEEPALIVE

上面提到,SO_KEEPALIVE默认的时间间隔太长,不利于应用程序检测连接状态。

解决方法有2种:

  • 全局设置
  • 针对单个连接设置

2.1 全局设置

在Linux中我们可以通过修改 /etc/sysctl.conf 的全局配置:

net.ipv4.tcp_keepalive_time=7200
net.ipv4.tcp_keepalive_intvl=75
net.ipv4.tcp_keepalive_probes=9

添加上面的配置后输入 sysctl -p 使其生效,

你可以使用命令来查看当前的默认配置

sysctl -a | grep keepalive

如果应用中已经设置SO_KEEPALIVE,程序不用重启,内核直接生效.

这种方法设置的全局的参数,针对整个系统生效,对单个socket的设置不够友好。

2.2 针对单个连接设置

我们可以使用TCP的TCP_KEEPCNTTCP_KEEPIDLETCP_KEEPINTVL3个选项。

这些选项是连接级别的,每个socket都可以设置这些属性。

这些选项的定义,可以通过man查看。

man 7 tcp

socket option:

TCP_KEEPCNT (since Linux 2.4)
The maximum number of keepalive probes TCP should send before
dropping the connection. This option should not be used in
code intended to be portable.
关闭一个非活跃连接之前的最大重试次数。
该选项不具备可移植性。 TCP_KEEPIDLE (since Linux 2.4)
The time (in seconds) the connection needs to remain idle
before TCP starts sending keepalive probes, if the socket
option SO_KEEPALIVE has been set on this socket. This option
should not be used in code intended to be portable.
设置连接上如果没有数据发送的话,多久后发送keepalive探测分组,单位是秒
该选项不具备可移植性。 TCP_KEEPINTVL (since Linux 2.4)
The time (in seconds) between individual keepalive probes.
This option should not be used in code intended to be
portable.
前后两次探测之间的时间间隔,单位是秒
该选项不具备可移植性。

代码层面的设置步骤:

int keepAlive = 1;    // 非0值,开启keepalive属性

int keepIdle = 60;    // 如该连接在60秒内没有任何数据往来,则进行此TCP层的探测

int keepInterval = 5; // 探测发包间隔为5秒

int keepCount = 3;        // 尝试探测的最多次数

// 开启探活
setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, (void *)&keepAlive, sizeof(keepAlive)); setsockopt(sockfd, SOL_TCP, TCP_KEEPIDLE, (void*)&keepIdle, sizeof(keepIdle)); setsockopt(sockfd, SOL_TCP, TCP_KEEPINTVL, (void *)&keepInterval, sizeof(keepInterval)); setsockopt(sockfd, SOL_TCP, TCP_KEEPCNT, (void *)&keepCount, sizeof(keepCount)

3.为什么应用层需要heart beat/心跳包?

通过上面的介绍,感觉TCP keepalive已经很牛逼了,但为什么还会提到应用层的心跳呢?

目前了解的原因包括两个:

  • TCP keepalive处于传输层,由操作系统负责,能够判断进程存在,网络通畅,但无法判断进程阻塞或死锁等问题。
  • 客户端与服务器之间有四层代理或负载均衡,即在传输层之上的代理,只有传输层以上的数据才被转发,例如socks5等

所以,基于以上原因,有时候还是需要应用程序自己去设计心跳规则的。

可以服务端负责周期发送心跳包,检测客户端,也可以客户端负责发送心跳包,或者服服务端和客户端同时发送心跳包。

可以根据具体的应用场景进行设计。

参考

《UNIX网络编程卷1》

《Linux多线程服务端编程》

man 7 tcp

setsockopt, SO_KEEPALIVE and Heartbeats

为什么基于TCP的应用需要心跳包(TCP keep-alive原理分析

TCP中已有SO_KEEPALIVE选项,为什么还要在应用层加入心跳包机制

微信的大规模使用真的会过多占用信令,影响通讯稳定吗

TCP keepalive的详解(解惑)的更多相关文章

  1. HTTP协议头部与Keep-Alive模式详解

    HTTP协议头部与Keep-Alive模式详解 .什么是Keep-Alive模式? 我们知道HTTP协议采用“请求-应答”模式,当使用普通模式,即非KeepAlive模式时,每个请求/应答客户和服务器 ...

  2. HTTP协议Keep-Alive模式详解

    详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcytp22 HTTP协议Keep-Alive模式详解 1.什么是Keep-Aliv ...

  3. TCP/IP协议详解概述

    TCP/IP协议详解卷1--第一章概述--读书笔记 作者:vpoet 日期:2015/06/25 注:本系列的文章只是作者对TCP/IP协议的理解,难免会出现纰漏或者不完整,当然也有可能很肤浅,希望大 ...

  4. 【转载】TCP /IP协议详解

    首先,TCP/IP不是一个协议,而是一个协议族的统称. 里面包括了IP协议,IMCP协议,TCP协议,以及http.ftp.pop3协议等等. TCP/IP协议分层 提到协议分层,我们很容易联想到IS ...

  5. TCP、UDP详解与抓包工具使用

    参考:https://www.cnblogs.com/HPAHPA/p/7737641.html TCP.UDP详解 1.传输层存在的必要性 由于网络层的分组传输是不可靠的,无法了解数据到达终点的时间 ...

  6. [转]TCP滑动窗口详解

    TCP滑动窗口详解  http://lyjdamzwf.blog.163.com/blog/static/75206837201193373226/ TCP滑动窗口(Sliding Window)   ...

  7. TCP/IP协议详解---概述

        工作之后,才发现以前在学校里学的东西忘得太快太干净了,现在需要一点点地捡起来了,要不然写几行程序会闹很多笑话会出现很多bug的.从今天开始,翻一翻<TCP/IP协议详解 卷1>这本 ...

  8. TCP /IP协议详解【转】

    转自:https://www.jianshu.com/p/0cf648510bce?utm_campaign=maleskine&utm_content=note&utm_medium ...

  9. 计算机网络(三),TCP报文段详解

    目录 1.TCP(Transmission Control Protocol传输控制协议)作用 2.TCP报文段详解 三.TCP报文段详解 1.TCP(Transmission Control Pro ...

随机推荐

  1. Redis位操作介绍

    在学习redis的过程了,看到了redis还能用于大数据处理,具体场景如下:腾讯10亿用户,要几个毫秒内查询到某个用户是否在线,你能怎么做?千万别说给每个用户建立一个key,然后挨个记(你可以算一下需 ...

  2. Linux 的终端 Terminal

    打开终端: 方式一:在全部应用中搜索Terminal 方式二:Ctrl+Alt+T 快捷方式打开终端 终端指令查询 如果忘记终端指令而只记得前几位可以只输入前几个字母后按Tab键查询 终端清屏 键入c ...

  3. STARTUPINFO结构体

    typedef struct _STARTUPINFO { DWORD cb; //包含STARTUPINFO结构中的字节数.如果Microsoft将来扩展该结构,它可用作版本控制手段.应用程序必须将 ...

  4. PropertyPlaceholderConfigurer implements BeanFactoryPostProcessor

    BeanFactoryPostProcessor的应用 最常用的一个应用就是org.springframework.beans.factory.config.PropertyPlaceholderCo ...

  5. linux下redis 安装

    --获取redis [redis@localhost ~]$ wget http://download.redis.io/releases/redis-2.8.7.tar.gz --2017-05-2 ...

  6. P1801 黑匣子[对顶堆]

    没错我就是专门找对顶堆练习题的.现在感觉对顶堆使用面有点狭窄.这道题由于我询问是随时间单调增的,而且数据比较友好,应该是插入几次就询问一下的.而中位数那题也是经常询问的.如果查询的东西不单调,或者查询 ...

  7. React native 在mac下安裝 环境

    前言 春节回来上班第一天,配了mac ,然后在去年就有要弄mac 配置RN教程,好勒一上午,其中有遇到一些问题,都解决 了 当然你可以看官网的步骤啦 https://reactnative.cn/do ...

  8. Acwing-280-陪审团(背包dp?)

    链接: https://www.acwing.com/problem/content/282/ 题意: 在一个遥远的国家,一名嫌疑犯是否有罪需要由陪审团来决定. 陪审团是由法官从公民中挑选的. 法官先 ...

  9. TCP下的套接字服务端实现并发 作业题

    # 服务端 import socket from threading import Thread """ 服务端 1.要有固定的IP和PORT 2.24小时不间断提供服务 ...

  10. qt5--数据类型转换

    QString-->Char*        str.toUtf8().data() pointf=QPointF(point);       //将QPoint转换为QPointF point ...