KeepAlive并不是TCP协议规范的一部分,但在几乎所有的TCP/IP协议栈(不管是Linux还是Windows)中,都实现了KeepAlive功能

RFC1122#TCP Keep-Alives

如何设置它?

在设置之前我们先来看看KeepAlive都支持哪些设置项

  1. KeepAlive默认情况下是关闭的,可以被上层应用开启和关闭
  2. tcp_keepalive_time: KeepAlive的空闲时长,或者说每次正常发送心跳的周期,默认值为7200s(2小时)
  3. tcp_keepalive_intvl: KeepAlive探测包的发送间隔,默认值为75s
  4. tcp_keepalive_probes: 在tcp_keepalive_time之后,没有接收到对方确认,继续发送保活探测包次数,默认值为9(次)

我们讲讲在Linux操作系统和使用Java、C语言和Nginx中如何设置

在Linux内核设置

KeepAlive默认不是开启的,如果想使用KeepAlive,需要在你的应用中设置SO_KEEPALIVE才可以生效。

查看当前的配置:

1
2
3
cat /proc/sys/net/ipv4/tcp_keepalive_time
cat /proc/sys/net/ipv4/tcp_keepalive_intvl
cat /proc/sys/net/ipv4/tcp_keepalive_probes

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

1
2
3
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,程序不用重启,内核直接生效

使用Netty4设置

这里我们使用常用的Java网络框架Netty来设置,只需要在服务端设置即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
EventLoopGroup bossGroup   = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
    ServerBootstrap b = new ServerBootstrap();
    b.group(bossGroup, workerGroup)
            .channel(NioServerSocketChannel.class)
            .option(ChannelOption.SO_BACKLOG, 100)
            .childOption(ChannelOption.SO_KEEPALIVE, true)
            .handler(new LoggingHandler(LogLevel.INFO));
 
    // Start the server.
    ChannelFuture f = b.bind(8088).sync();
    // Wait until the server socket is closed.
    f.channel().closeFuture().sync();
} finally {
    // Shut down all event loops to terminate all threads.
    bossGroup.shutdownGracefully();
    workerGroup.shutdownGracefully();
}

这段代码来自经典的echo服务器,我们在childOption中开启了SO_KEEPALIVE。 Java程序只能做到设置SO_KEEPALIVE选项,其他配置项只能依赖于sysctl配置,系统进行读取。

C语言设置

函数原型:

1
2
3
4
#include <sys/socket.h>
 
int setsockopt(int socket, int level, int option_name,
      const void *option_value, socklen_t option_len);

我们在需要使能Keepalive的socket上面调用setsockopt函数便可以打开该socket上面的keepalive。

  1. 第一个参数是要设置的套接字
  2. 第二个参数是SOL_SOCKET
  3. 第三个参数必须是SO_KEEPALIVE
  4. 第四个参数必须是一个布尔整型值,0表示关闭,1表示打开
  5. 最后一个参数是第四个参数值的大小。

调用例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
int socket(int domain, int type, int protocol)
{
  int (*libc_socket)(int, int, int);
  int s, optval;
  char *env;
 
  *(void **)(&libc_socket) = dlsym(RTLD_NEXT, "socket");
  if(dlerror()) {
    errno = EACCES;
    return -1;
  }
 
  if((s = (*libc_socket)(domain, type, protocol)) != -1) {
    if((domain == PF_INET) && (type == SOCK_STREAM)) {
      if(!(env = getenv("KEEPALIVE")) || strcasecmp(env, "off")) {
        optval = 1;
      } else {
        optval = 0;
      }
      if(!(env = getenv("KEEPALIVE")) || strcasecmp(env, "skip")) {
        setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval));
      }
#ifdef TCP_KEEPCNT
      if((env = getenv("KEEPCNT")) && ((optval = atoi(env)) >= 0)) {
        setsockopt(s, SOL_TCP, TCP_KEEPCNT, &optval, sizeof(optval));
      }
#endif
#ifdef TCP_KEEPIDLE
      if((env = getenv("KEEPIDLE")) && ((optval = atoi(env)) >= 0)) {
        setsockopt(s, SOL_TCP, TCP_KEEPIDLE, &optval, sizeof(optval));
      }
#endif
#ifdef TCP_KEEPINTVL
      if((env = getenv("KEEPINTVL")) && ((optval = atoi(env)) >= 0)) {
        setsockopt(s, SOL_TCP, TCP_KEEPINTVL, &optval, sizeof(optval));
      }
#endif
    }
  }
 
   return s;
}

代码摘取自libkeepalive源码,C语言可以设置更为详细的TCP内核参数

在Nginx中配置

在Nginx中配置TCP的KeepAlive非常简单,在listen指令下配置so_keepalive就可以了,具体配置

1
so_keepalive=on|off|[keepidle]:[keepintvl]:[keepcnt]

this parameter (1.1.11) configures the “TCP keepalive” behavior for the listening socket. If this parameter is omitted then the operating system’s settings will be in effect for the socket. If it is set to the value “on”, the SO_KEEPALIVE option is turned on for the socket. If it is set to the value “off”, the SO_KEEPALIVE option is turned off for the socket. Some operating systems support setting of TCP keepalive parameters on a per-socket basis using the TCP_KEEPIDLE, TCP_KEEPINTVL, and TCP_KEEPCNT socket options. On such systems (currently, Linux 2.4+, NetBSD 5+, and FreeBSD 9.0-STABLE), they can be configured using the keepidle, keepintvl, and keepcnt parameters. One or two parameters may be omitted, in which case the system default setting for the corresponding socket option will be in effect.

例子

1
2
3
4
so_keepalive=30m::10
will set the idle timeout (TCP_KEEPIDLE) to 30 minutes,
leave the probe interval (TCP_KEEPINTVL) at its system default,
and set the probes count (TCP_KEEPCNT) to 10 probes.

使用的场景

一般我们使用KeepAlive时会修改空闲时长,避免资源浪费,系统内核会为每一个TCP连接 建立一个保护记录,相对于应用层面效率更高。

常见的几种使用场景:

  1. 检测挂掉的连接(导致连接挂掉的原因很多,如服务停止、网络波动、宕机、应用重启等)
  2. 防止因为网络不活动而断连(使用NAT代理或者防火墙的时候,经常会出现这种问题)
  3. TCP层面的心跳检测

KeepAlive通过定时发送探测包来探测连接的对端是否存活, 但通常也会许多在业务层面处理的,他们之间的特点:

  1. TCP自带的KeepAlive使用简单,发送的数据包相比应用层心跳检测包更小,仅提供检测连接功能
  2. 应用层心跳包不依赖于传输层协议,无论传输层协议是TCP还是UDP都可以用
  3. 应用层心跳包可以定制,可以应对更复杂的情况或传输一些额外信息
  4. KeepAlive仅代表连接保持着,而心跳包往往还代表客户端可正常工作

和Http中Keep-Alive的关系

  1. HTTP协议的Keep-Alive意图在于连接复用,同一个连接上串行方式传递请求-响应数据
  2. TCP的KeepAlive机制意图在于保活、心跳,检测连接错误

参考资料

http://www.importnew.com/27624.html

聊聊 TCP 中的 KeepAlive 机制的更多相关文章

  1. TCP中的KeepAlive与HTTP中的Keep-Alive

    KeepAlive 与 Keep-Alive 前言 昨天被问到了HTTP中Keep-Alive的概念,看名字我只知道是保持连接用的,但是对于他怎么结束连接,为什么要用他这些就不是很清楚了,今天查了一下 ...

  2. 闲说HeartBeat心跳包和TCP协议的KeepAlive机制

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

  3. tcp中的keepalive(转)

    理解Keepalive(1) 大家都听过keepalive,但是其实对于keepalive这个词还是很晦涩的,至少我一直都只知道一个大概,直到之前排查线上一些问题,发现keepalive还是有很多玄机 ...

  4. 结合实战和源码来聊聊Java中的SPI机制?

    写在前面 SPI机制能够非常方便的为某个接口动态指定其实现类,在某种程度上,这也是某些框架具有高度可扩展性的基础.今天,我们就从源码级别深入探讨下Java中的SPI机制. 注:文章已收录到:https ...

  5. IE中Keep-Alive机制引起的错误

    我们知道Http协议是基于TCP/IP连接的,也就是说客户端浏览器向服务器发出一个Http请求并得到响应是要建立一条TCP/IP连接的,但是如果每发出一个Http请求客户端就要向服务器端建立一条TCP ...

  6. TCP连接探测中的Keepalive和心跳包. 关键字: tcp keepalive, 心跳, 保活

    1. TCP保活的必要性 1) 很多防火墙等对于空闲socket自动关闭 2) 对于非正常断开, 服务器并不能检测到. 为了回收资源, 必须提供一种检测机制. 2. 导致TCP断连的因素 如果网络正常 ...

  7. 在Linux环境下使用TCP的keepalive机制

    Linux内置支持keepalive机制,为了使用它,你须要使能TCP/IP网络,为了可以配置内核在执行时的參数.你还须要procfs和sysctl的支持. 这个过程涉及到keepalive使用的三个 ...

  8. SCRIPT7002: XMLHttpRequest: 网络错误 0x2ef3, 由于出现错误 00002ef3 而导致此项操作无法完成,浏览器中的Keep-Alive

    http://www.cnblogs.com/OpenCoder/p/5089258.html     IE中Keep-Alive机制引起的错误 我们知道Http协议是基于TCP/IP连接的,也就是说 ...

  9. TCP漫谈之keepalive和time_wait

    TCP是一个有状态通讯协议,所谓的有状态是指通信过程中通信的双方各自维护连接的状态. 一.TCP keepalive 先简单回顾一下TCP连接建立和断开的整个过程.(这里主要考虑主流程,关于丢包.拥塞 ...

随机推荐

  1. 企业级任务调度框架Quartz(4) 多个job实例注册到任务调度器上

    前序:     在第一个例子我看到了自定义的作业类在任务调度器上注册后,则通过任务调度器来实现启动:下面,我们将同一个作业类执行两个任务,并都将他们注册到任务调度器上!     首先一个job类指向两 ...

  2. 使用dom4j生成word的方法

    http://blog.csdn.net/zhyh1986/article/details/8727523#t6 http://blog.csdn.net/zuozuofuwaiwai/article ...

  3. 洛谷P2038 无线网络发射器选址 水题 枚举

    刚开始边界写错了(将128写成127). 注意n <= 20,所以可以每读入一个点就将其周边更新,这样最多也只会有 40 * 40 * 20 种位置需要被枚举. Code: #include&l ...

  4. 【路飞学城Day170】算法小结

    Evernote Export 算法的思想是能省则省,内存能少则少,时间运行能少尽量少 堆排序的时间复杂度O(nlogn) 堆排序的内置模块heapq 常用函数 heapify(x) heappush ...

  5. 【BZOJ3451】Tyvj1953 Normal - 点分治+FFT

    题目来源:NOI2019模拟测试赛(七) 非原题面,题意有略微区别 题意: 吐槽: 心态崩了. 好不容易场上想出一题正解,写了三个小时结果写了个假的点分治,卡成$O(n^2)$ 我退役吧. 题解: 原 ...

  6. nyoj158-省赛来了

    省赛来了 时间限制:1000 ms  |  内存限制:65535 KB 难度:2 描述 一年一度的河南省程序设计大赛又要来了. 竞赛是要组队的,组队形式:三人为一队,设队长一名,队员两名. 现在问题就 ...

  7. [tyvj-1391]走廊泼水节 最小生成树

    做克鲁斯卡尔的时候维护一个并查集即可. #include <iostream> #include <cstdio> #include <cstring> #incl ...

  8. Flask-SQLAlchemy中解决数据库连接1366报错

    报错信息:Warning: (1366, "Incorrect string value: '\\xD6\\xD0\\xB9\\xFA\\xB1\\xEA...' for column 'V ...

  9. Problem 9

    Problem 9 # Problem_9.py """ A Pythagorean triplet is a set of three natural numbers, ...

  10. 使用maven服务器插件 运行项目

    使用jetty插件  部署运行 创建一个maven项目:去Maven仓库中寻找jetty插件  然后复制到pom.xml中 使用命令  运行程序: 然后控制台打印: 通过浏览器   访问: ----- ...