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相應的處理函數非常easy,就是讓備份機開始執行:
static void tcpkeepalive_vm_start(void *opaque) { vm_start(); }