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

Linux内置支持keepalive机制,为了使用它,你需要使能TCP/IP网络,为了能够配置内核在运行时的参数,你还需要procfs和sysctl的支持。

这个过程涉及到keepalive使用的三个用户驱使的变量:

tcp_keepalive_time:表示的是最近一次数据包(简单的不含数据的ACKs包)发送与第一次keepalive探针发送之间的时间间隔;当连接被标记为keepalive之后,这个计数器就不会再使用。

tcp_keepalive_intvl:表示的是并发keepalive探针之间的时间间隔。

tcp_keepalive_probes:在确定连接已经断开并且通知应用层之前所发送的没有得到回复的探针数。

对于这三个参数可以在Linux系统的终端中查看和修改它们的缺省值:

查看三个参数的值:

[[email protected] ~]# cat /proc/sys/net/ipv4/tcp_keepalive_time
7200
[[email protected] ~]# cat /proc/sys/net/ipv4/tcp_keepalive_intvl
75
[[email protected] ~]# cat /proc/sys/net/ipv4/tcp_keepalive_probes
9

通过命令对这三个参数值进行修改(图中将三个参数值分别设为:600、60、20):

[[email protected] ~]# echo 600 > /proc/sys/net/ipv4/tcp_keepalive_time
[[email protected] ~]# echo 60 > /proc/sys/net/ipv4/tcp_keepalive_intvl
[[email protected] ~]# echo 6 > /proc/sys/net/ipv4/tcp_keepalive_probes

这种方式重置三个参数值,在系统重启后三个参数的值又会恢复到默认值,具体如何让系统永远记住自己设置的值,可参考其他资料,我们现在关系的是如何在程序中使用keepalive机制并设置这三个参数的值。

在程序中使用keepalive机制

想在程序中使用这种机制,只需要使用setsockopt()函数。

setsockopt()函数用于任意类型、任意状态套接口的设置选项值。尽管在不同协议层上存在选项,但本函数仅定义了最高的“套接口”层次上的选项。选项影响套接口的操作,诸如加急数据是否在普通数据流中接收,广播数据是否可以从套接口发送等等。

下面为setsockopt()函数的原型:

#include <sys/types.h>
#include <sys/socket.h>
int setsockopt(int sock, int level, int optname, const void *optval, socklen_t optlen);

参数:

sock:将要被设置或者获取选项的套接字。

level:选项所在的协议层。

optname:需要访问的选项名。

optval:对于getsockopt(),指向返回选项值的缓冲。对于setsockopt(),指向包含新选项值的缓冲。

optlen:对于getsockopt(),作为入口参数时,选项值的最大长度。作为出口参数时,选项值的实际长度。对于setsockopt(),现选项的长度。

为了使用函数setsockopt()将某个特定的套接字的keepalive机制打开,参数s是一个socket文件描述符,必须要在这之前使用socket()函数进行创建;参数level必须设置为SOL_SOCKET;第三个参数必须设置为SO_KEEPALIVE;optval参数必须是一个布尔型整型变量,表示想要使能这个选项;最后一个参数表示第四个参数的大小。

程序实现心跳包检测机制

首先要在备份机和源机之间建立一个专门的socket链路来进行心跳检测。

在源机端,在进行数据迁移之前,会建立一个socket来监听备份机的连接,并将这个socket和对应的处理函数放入原软件的io处理列表中,代码如下:

int listenfd;
    struct sockaddr_in server_sin;

    /* establish socket */
    listenfd=socket(AF_INET,SOCK_STREAM,0);
    server_sin.sin_family=AF_INET;
    server_sin.sin_addr.s_addr=htonl(INADDR_ANY);
    server_sin.sin_port=htons(PORT);
    bind(listenfd,(struct sockaddr *)&server_sin,sizeof(server_sin));
    /* establish end */

    listen(listenfd,1024);

    qemu_set_fd_handler2(listenfd, NULL, tcpkeepalive_server, NULL,
                         (void *)(intptr_t)listenfd);

该socket对应的处理函数如下:

static void tcpkeepalive_server(void *opaque)
{
    int connfd;
    struct sockaddr_in client_sin;
    socklen_t client_len=sizeof(client_sin);
    int listenfd = (intptr_t)opaque;

    connfd=accept(listenfd,(struct sockaddr *)&client_sin,&client_len);
}

在备份机端,当其开始作为备份机时,会建立socket连接源机的监听端,并设置对应的tcpkeepalive参数,然后将socket和对应的处理函数加入io处理列表。

我们建立的socket是一个心跳检测专用链路,其上不会有数据流动,只有一种情况备份机端会收到数据,那就是源端出现了故障,tcpkeepalive机制会返回一个错误信息,所以捕捉到了这个信息,备份机就会跳转到对应的处理函数,接替源机开始运行。

对应代码如下:

int sockfd;
    struct sockaddr_in sin;

    int optval;
    socklen_t optlen = sizeof(optval);

    sockfd=socket(AF_INET,SOCK_STREAM,0);
    sin.sin_family=AF_INET;
    sin.sin_addr.s_addr=addr.sin_addr.s_addr;
    sin.sin_port=htons(PORT);

    optval = 1;
    setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &optval, optlen);

    optval = 5;
    setsockopt(sockfd, SOL_TCP, TCP_KEEPCNT, &optval, optlen);

    optval = 1;
    setsockopt(sockfd, SOL_TCP, TCP_KEEPIDLE, &optval, optlen);

    optval = 1;
    setsockopt(sockfd, SOL_TCP, TCP_KEEPINTVL, &optval, optlen);

    connect(sockfd,(struct sockaddr *)&sin,sizeof(sin));

    qemu_set_fd_handler2(sockfd, NULL, tcpkeepalive_vm_start, NULL,
                         (void *)(intptr_t)sockfd);

该socket对应的处理函数很简单,就是让备份机开始运行:

static void tcpkeepalive_vm_start(void *opaque)
{
    vm_start();
}

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

时间: 2024-11-05 13:35:27

在Linux环境下使用TCP的keepalive机制的相关文章

mosquitto在Linux环境下的部署/安装/使用/测试

mosquitto在Linux环境下的部署 看了有三四天的的源码,(当然没怎么好好看了),突然发现对mosquitto的源码有了一点点感觉,于是在第五天决定在Linux环境下部署mosquitto. 使用传统源码安装步骤: 步骤1:http://mosquitto.org/files/source/官网下载源码,放到Linux环境中.解压后,找到主要配置文件config.mk,其中包含mosquitto的安装选项,需要注意的是,默认情况下mosquitto的安装需要OpenSSL(一个强大的安全

【转载】linux环境下tcpdump源代码分析

linux环境下tcpdump源代码分析 原文时间 2013-10-11 13:13:02   原文链接   主题 Tcpdump 作者:韩大卫 @ 吉林师范大学 tcpdump.c 是tcpdump 工具的main.c, 本文旨对tcpdump的框架有简单了解,只展示linux平台使用的一部分核心代码. Tcpdump 的使用目的就是打印出指定条件的报文,即使有再多的正则表达式作为过滤条件.所以只要懂得tcpdump -nXXi eth0 的实现原理即可. 进入main之前,先看一些头文件 n

linux环境下配置jdk+tomcat环境

最近在学习java,其中最重要的一项是将jdk 环境配置好,同时在jdk中结合tomcat开发基于应用,所以在这里记录下. 配置环境: 系统环境:centos 6.3  64位 ,jdk:jdk-6u29-linux-x64.bin ,  tomcat:apache-tomcat-6.0.35.zip  这里需要注意的地方是  jdk 安装时要和系统位数相同,这里我的系统是64位所以这里使用的是jdk 64 位. 开始配置: 这里我将要安装的软件,上传到/usr/loca/目录下,使用 rz 

Windows/Linux环境下模拟服务端口方法

场景需求: 对于涉及纵向级联(比如与总部.分部级联)或横向互联(与本级其他系统互联)的大系统,往往需要在未部署系统服务时验证相关端口的开通情况,以备在防火墙上进行端口开通申请. Windows环境下模拟服务端口: 在服务器端使用第三方软件"TCP&UDP测试工具"进行模拟端口,可以很方面的用"telnet  ip  port"命令测试. Linux环境下模拟服务端口: 可以使用"nc  -v  ip  port"命令测试端口是否开通,若提

ojdbc在linux环境下 java.sql.SQLRecoverableException: IO Error: Connection reset 的问题

开门见山,最快捷的解决方案:java -Djava.security.egd=file:///dev/urandom  -jar  xxxxxxx.jar 描述下问题:写了个jar工具,用到了连接池,ojdbc.windows环境一起正常.linux环境下启动关闭两三次后就出现 java.sql.SQLRecoverableException: IO 错误: Connection reset 查看配置文件和解析问题, 无果. 更换hikari到druid,无果. 使用最新ojdbc包,无果. 无

(1)Jenkins Linux环境下的简单搭建

(1)Jenkins Linux环境下的简单搭建 Jenkins是一个开源软件项目,旨在提供一个开放易用的软件平台,使软件的持续集成变成可能. ----百度百科 这是一款基于Java开发的工具.种种原因,最近刚开始接触,决定研究一下.Jenkins的搭建方法不止一种,一下就是个人总结的其中一种,文章内容比较浅显,不足之处,欢迎指正. 首先,所需要准备的工具JDK.Maven.资料上显示JDK版本最好高于1.7,并没有研究1.7以下版本,所谓"没有实际调研,就没有发言权",在此就不做过多

Linux环境下线程消息同步的陷阱

我们程序中常常会使用到线程间的消息同步处理,比如以下一段伪码 var message = "": void func()  {   1. 启动线程Thread(该线程中填充message的内容):   2. 阻塞,直到等待到完成message填充的事件:   3. 处理message:   .... } void Thread()  {   1. 通过某种处理填充message:   2. 触发func中的阻塞事件: } 我们通常会使用条件变量来完成类似情况的线程同步处理 比如wind

ant+jmeter 在Linux环境下接口自动化测试环境搭建(2)

上一篇讲过在Windows下搭建的方法,今天这里写一下在Linux环境下搭建的方法. 实验准备:Linux服务器一台. 服务器上安装好jdk,配置好环境变量. 服务器上配置好ant. 工具准备: Jdk下载地址: http://www.oracle.com/technetwork/java/javase/downloads/index.html Jmeter下载地址 http://jmeter.apache.org/ Ant下载地址 http://ant.apache.org/ 环境准备: 所以

Linux环境下线程的同步与互斥以及死锁问题

由于本次要讨论操作系统的死锁问题,所以必须先研究的是linux环境下的线程同步与互斥 先看下面的代码 大家猜想输出应该是什么呢? 结果是下面这个样子 好吧,似乎并没有什么区别... 那么下面再看这段代码(请无视并忽略屏蔽的内容...) 大家猜想正确的结果是什么呢?5000,10000? 好吧,或许你们都错了. 在运行了一段时间后,它的结果是这样的. 是不是又对又错? 为什么呢? 这就是因为程序中printf语句作用:本身是库函数,所以必须进行系统调用,必须进入内核进行切换,有很大概率形成数据的混