1. 程式人生 > >在Linux環境下使用TCP的keepalive機制

在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環境 Redis 安裝、啟動、連線、主從複製、哨兵機制

安裝步驟 Linux 版本號 CentOS-6.4-x86_64 Redis 版本號 redis-3.0.6.tar.gz 1、usr資料夾中,建立redis資料夾 2、解壓 redis-3.0.6.tar.gz 3、解壓後進入到資料夾 redis-3.0.6 4、編譯 ma

Linux環境使用TCP的keepalive機制

Linux內建支援keepalive機制,為了使用它,你需要使能TCP/IP網路,為了能夠配置核心在執行時的引數,你還需要procfs和sysctl的支援。 這個過程涉及到keepalive使用的三個使用者驅使的變數: tcp_keepalive_time:表示的是最近一次

關於linux環境訊號SIGCHLD的排隊機制

一直對這個問題沒有深入的思考過。最近由於專案的需要終於弄清了這個問題。 以下文字是抄襲+理解+估計: 在linux系統中,子程序的正常/異常終止都會給父程序傳送SIGCHLD的訊號,當父程序接收到子程序(第一個)訊號進行wait()或waitpid()時,會遮蔽掉下一個的SIGCHLD訊號,實際的效果就

Linux環境的 pyenv的安裝

pyenvCentOS上安裝pyenv:在安裝pyenv前,需要先安裝如下的依賴包:在 CentOS/RHEL/Fedora 下:yum install readline readline-devel readline-static yum install openssl openssl-devel open

linux環境部署zabbix3.2、模板、郵件告警詳細過程

-1 ice erer without zlib zip ever native item 服務端部署: 系統環境及軟件版本: Linux:release 6.3 zabbix:zabbix-3.2.5.tar.gz nginx:nginx-1.12.0.tar.gz ph

2.Linux環境配置Solr4.10.3

margin 內容 src source -type alt 技術 tgz 安裝包 1.準備階段 操作系統:CentOS 6.8 安裝包:/home/test solr-4.10.3.tgz.tar IK Analyzer 2012FF_hf1.zip jdk-8u12

由一個簡單需求到Linux環境的syslog、unix domain socket

message python domain 服務器 import 需求:回到頂部  工作中有一個在Linux(debian8)環境下運行的服務器程序,用python語言實現,代碼中有不同優先級的日誌需要記錄,開發的時候都是使用python的logging模塊輸出到文件,示例代碼如下:  

(1)Jenkins Linux環境的簡單搭建

linux java jenkins安裝部署 jdk apache-maven (1)Jenkins Linux環境下的簡單搭建 Jenkins是一個開源軟件項目,旨在提供一個開放易用的軟件平臺,使軟件的持續集成變成可能。----百度百科 這是一款基於Java開發的工具。種種

linux 環境備份oracle 數據庫

備份 命令 目錄 lin 安裝目錄 su - linux 輸出 所有者 登陸linux後,進入oracle的安裝目錄下,找到bin那個目錄,進入bin目錄ls -l 看這些命令的所有者: su - oracle這時會進入這個用戶的主目錄/home/oracle,此時,可以用

將windows上面的項目拷貝到Linux環境報錯不能夠找到對應的表com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table 'puyang.ServiceType' doesn't exist

exce 服務 inux 區分 大小 blog alt logs 就會 將一模一樣的項目從win遷移到到linux上報錯: 一開始還是以為是linux不能識別hql語句,查找資料發現是因為Liunx服務器上mysql是區分大小寫的,而本地是不區分的如:代碼是這樣寫的@En

linux環境關於顯示日期及修改密碼的小練習

一只小菜鳥的成長1.顯示1984-11-18是1984年的第幾天 2.顯示當前的日期 ##上面是兩種不同的表現形式## 3.在超級用戶下修改student用戶的密碼,並且student用戶在第一次登錄後強制修改密碼 ## passwd -e ## 強制修改密碼##註意:當使用root用戶修改其他用戶密

Linux環境使用SSH判斷端口是否通

linux telnet redhat 在Linux環境下使用SSH判斷端口是否通在windows/linux環境下,可以使用telnet判斷端口狀態,但有時候在Linux環境下沒有telnet,所以可以使用ssh判斷端口狀態。 一、ssh使用方法:命令:ssh -v -p port [email

linux環境tomcat啟動成功,請求頁面出現404

無法 .html 奇怪 tomcat啟動 web訪問 第一次 裏的 同事 有變 這種情況很多,本文記錄我遇到比較奇葩的情況。 第一次tomact啟動成功,訪問404,亂搗鼓不知怎麽好了;第二次tomcat啟動成功,可以訪問部分鏈接,有些卻報404,但是代碼和數據都還是以前的

linux環境jdk部署配置

etc $path 是否 ssp java jdk1 配置系統 exp 執行文件 1、java官網下載相關的jdk包 2、配置系統環境變量,編輯/etc/profile文件,在文件的末尾添加一下信息: export JAVA_HOME=/usr/jdk1.8.0_101ex

eclipse遠程調試Linux環境的web項目

config pil logs .com xxx web declare 但是 遠程服務 前提: 遠程服務器上的代碼和本地的代碼同步 第一步 : 配置遠程服務器下的startup.sh文件   在第一行添加 : declare -x CATALINA_OPTS="-se

Linux環境安裝XAMPP的PHP的PDF擴展

dynamic obj directory -- lib mic php.ini ble 報錯 安裝pdf擴展1. wget http://pecl.php.net/get/pdflib-4.1.2.tgz2. tar zxvf pdflib-4.1.2.tgz3. cd

Linux環境啟動MySQL數據庫出現找不到mysqld.sock的解決辦法!

備註 sta 就會 超級 默認目錄 sql數據庫 su - 用戶 lib 問題:   在普通用戶權限下運行:mysql -u root -p,回車之後如果會出現如下錯誤:ERROR 2002 (HY000): Can‘t connect to local MySQL ser

linux環境pytesseract的安裝和央行征信中心的登錄驗證碼識別實戰

int tab 權限 linux a-z 都是 提示 解釋 text 首先是安裝,我參考的是這個 http://blog.csdn.net/xinghun_4/article/details/47860645 我是centos,使用yum yum install pyt

linux環境安裝nginx步驟

borde test nginx重啟 images roo g++ .tar.gz org syn 開始前,請確認gcc g++開發類庫是否裝好,默認已經安裝。   ububtu平臺編譯環境可以使用以下指令 apt-get install build-essential

Linux環境GNU, GCC, G++編譯器(轉)

c代碼 但是 關系 例如 ann name 語法規則 否則 int 一,GNU GNU是“GNU ‘s Not Unix”的遞歸縮寫, Stallman宣布GNU應當發音為Guh-NOO(革奴)以避免與new這個單詞混淆(註:Gnu在英文中原意為非洲牛羚,發音與new相同)