在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