qileilove

          blog已經轉移至github,大家請訪問 http://qaseven.github.io/

          在Linux環境下使用TCP的keepalive機制

           Linux內置支持keepalive機制,為了使用它,你需要使能TCP/IP網絡,為了能夠配置內核在運行時的參數,你還需要procfs和sysctl的支持。
            這個過程涉及到keepalive使用的三個用戶驅使的變量:
            tcp_keepalive_time:表示的是最近一次數據包(簡單的不含數據的ACKs包)發送與第一次keepalive探針發送之間的時間間隔;當連接被標記為keepalive之后,這個計數器就不會再使用。
            tcp_keepalive_intvl:表示的是并發keepalive探針之間的時間間隔。
            tcp_keepalive_probes:在確定連接已經斷開并且通知應用層之前所發送的沒有得到回復的探針數。
            對于這三個參數可以在Linux系統的終端中查看和修改它們的缺省值:
            查看三個參數的值:
          [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
            通過命令對這三個參數值進行修改(圖中將三個參數值分別設為: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
            這種方式重置三個參數值,在系統重啟后三個參數的值又會恢復到默認值,具體如何讓系統永遠記住自己設置的值,可參考其他資料,我們現在關系的是如何在程序中使用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();
            }

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

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

          導航

          統計

          常用鏈接

          留言簿(55)

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 军事| 曲阳县| 日土县| 教育| 曲靖市| 潮州市| 和龙市| 三河市| 淮南市| 镇巴县| 林甸县| 青田县| 富顺县| 平罗县| 红河县| 仪陇县| 伊通| 射洪县| 靖安县| 赞皇县| 红河县| 天柱县| 宿松县| 哈密市| 湘阴县| 应用必备| 宁强县| 榆树市| 屏东市| 常德市| 九龙城区| 资阳市| 高安市| 蒲城县| 武平县| 珠海市| 达日县| 探索| 当涂县| 连城县| 诸暨市|