qileilove

          blog已經(jīng)轉(zhuǎn)移至github,大家請訪問 http://qaseven.github.io/

          在Linux環(huán)境下使用TCP的keepalive機制

           Linux內(nèi)置支持keepalive機制,為了使用它,你需要使能TCP/IP網(wǎng)絡,為了能夠配置內(nèi)核在運行時的參數(shù),你還需要procfs和sysctl的支持。
            這個過程涉及到keepalive使用的三個用戶驅(qū)使的變量:
            tcp_keepalive_time:表示的是最近一次數(shù)據(jù)包(簡單的不含數(shù)據(jù)的ACKs包)發(fā)送與第一次keepalive探針發(fā)送之間的時間間隔;當連接被標記為keepalive之后,這個計數(shù)器就不會再使用。
            tcp_keepalive_intvl:表示的是并發(fā)keepalive探針之間的時間間隔。
            tcp_keepalive_probes:在確定連接已經(jīng)斷開并且通知應用層之前所發(fā)送的沒有得到回復的探針數(shù)。
            對于這三個參數(shù)可以在Linux系統(tǒng)的終端中查看和修改它們的缺省值:
            查看三個參數(shù)的值:
          [root@Server3 ~]# cat /proc/sys/net/ipv4/tcp_keepalive_time
          7200
          [root@Server3 ~]# cat /proc/sys/net/ipv4/tcp_keepalive_intvl
          75
          [root@Server3 ~]# cat /proc/sys/net/ipv4/tcp_keepalive_probes
          9
            通過命令對這三個參數(shù)值進行修改(圖中將三個參數(shù)值分別設為:600、60、20):
            [root@Server3 ~]# echo 600 > /proc/sys/net/ipv4/tcp_keepalive_time
            [root@Server3 ~]# echo 60 > /proc/sys/net/ipv4/tcp_keepalive_intvl
            [root@Server3 ~]# echo 6 > /proc/sys/net/ipv4/tcp_keepalive_probes
            這種方式重置三個參數(shù)值,在系統(tǒng)重啟后三個參數(shù)的值又會恢復到默認值,具體如何讓系統(tǒng)永遠記住自己設置的值,可參考其他資料,我們現(xiàn)在關系的是如何在程序中使用keepalive機制并設置這三個參數(shù)的值。
            在程序中使用keepalive機制
            想在程序中使用這種機制,只需要使用setsockopt()函數(shù)。
            setsockopt()函數(shù)用于任意類型、任意狀態(tài)套接口的設置選項值。盡管在不同協(xié)議層上存在選項,但本函數(shù)僅定義了最高的“套接口”層次上的選項。選項影響套接口的操作,諸如加急數(shù)據(jù)是否在普通數(shù)據(jù)流中接收,廣播數(shù)據(jù)是否可以從套接口發(fā)送等等。
            下面為setsockopt()函數(shù)的原型:
            #include <sys/types.h>
            #include <sys/socket.h>
            int setsockopt(int sock, int level, int optname, const void *optval, socklen_t optlen);
            參數(shù):
            sock:將要被設置或者獲取選項的套接字。
            level:選項所在的協(xié)議層。
            optname:需要訪問的選項名。
            optval:對于getsockopt(),指向返回選項值的緩沖。對于setsockopt(),指向包含新選項值的緩沖。
            optlen:對于getsockopt(),作為入口參數(shù)時,選項值的最大長度。作為出口參數(shù)時,選項值的實際長度。對于setsockopt(),現(xiàn)選項的長度。
            為了使用函數(shù)setsockopt()將某個特定的套接字的keepalive機制打開,參數(shù)s是一個socket文件描述符,必須要在這之前使用socket()函數(shù)進行創(chuàng)建;參數(shù)level必須設置為SOL_SOCKET;第三個參數(shù)必須設置為SO_KEEPALIVE;optval參數(shù)必須是一個布爾型整型變量,表示想要使能這個選項;最后一個參數(shù)表示第四個參數(shù)的大小。
           程序?qū)崿F(xiàn)心跳包檢測機制
            首先要在備份機和源機之間建立一個專門的socket鏈路來進行心跳檢測。
            在源機端,在進行數(shù)據(jù)遷移之前,會建立一個socket來監(jiān)聽備份機的連接,并將這個socket和對應的處理函數(shù)放入原軟件的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對應的處理函數(shù)如下:
          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連接源機的監(jiān)聽端,并設置對應的tcpkeepalive參數(shù),然后將socket和對應的處理函數(shù)加入io處理列表。
            我們建立的socket是一個心跳檢測專用鏈路,其上不會有數(shù)據(jù)流動,只有一種情況備份機端會收到數(shù)據(jù),那就是源端出現(xiàn)了故障,tcpkeepalive機制會返回一個錯誤信息,所以捕捉到了這個信息,備份機就會跳轉(zhuǎn)到對應的處理函數(shù),接替源機開始運行。
            對應代碼如下:
          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對應的處理函數(shù)很簡單,就是讓備份機開始運行:
            static void tcpkeepalive_vm_start(void *opaque)
            {
            vm_start();
            }

          posted on 2014-05-19 10:17 順其自然EVO 閱讀(1063) 評論(0)  編輯  收藏 所屬分類: linux

          <2014年5月>
          27282930123
          45678910
          11121314151617
          18192021222324
          25262728293031
          1234567

          導航

          統(tǒng)計

          常用鏈接

          留言簿(55)

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 义乌市| 兴海县| 贵州省| 随州市| 巴东县| 漳浦县| 贺兰县| 娄底市| 甘肃省| 康平县| 罗山县| 拉萨市| 昌宁县| 图们市| 八宿县| 板桥市| 霍城县| 西丰县| 兰西县| 广丰县| 宝丰县| 胶州市| 赤峰市| 祁连县| 洪洞县| 鹤庆县| 万山特区| 阿勒泰市| 堆龙德庆县| 察雅县| 呼伦贝尔市| 财经| 高陵县| 太谷县| 东乡族自治县| 临西县| 正阳县| 县级市| 中卫市| 大兴区| 柳河县|