轉載:http://blog.csdn.net/embedded_sky/article/details/42077321
對於TCP長連接保活是十分必要的,原因如下:
1、系統多在OA網和外網間有防火牆隔離,很多防火牆對一段時間內沒有報文活動的socket會自動關閉。
2、對於非正常斷開的連接系統並不能偵測到,比如防火牆關閉端口、網線被拔掉、電腦突然奔掉、未關閉應用程序直接關機(服務端無法釋放資源)。
(調用close(fd)為正常斷開,連接對端可以偵測到)
TCP長連接保持的兩種辦法:
1) 應用層面的心跳機制
自定義心跳消息頭.,一般客戶端主動發送到服務端,服務器接收后進行回應(也可以不回應),以便能夠偵測連接是否異常斷開。
2) TCP協議自帶的保活功能
通過設置TCP keepalive的屬性,打開socket的keepalive屬性,並設置發送底層心跳包的時間間隔。TCP/IP五層網絡模型,我們調用socket等接口是應用層的函數,TCP keepalive是在底層定時發送心跳報文,服務器端接收到底層的心跳報文直接丟棄,不關心其內容。
使用TCP keepalive來保持長連接狀態顯然要舒服一些,直接調用系統的API即可實現,對於系統而言負擔也更輕(相對第一種辦法)。
以下是windows下TCP keepalive設置的函數:
1 /*@author super bert 2014-12-16*/ 2 /*socket TCP保持長連接函數*/ 3 int socket_tcp_alive(int socket) 4 { 5 int ret = 0; 6 7 int keep_alive = 1; 8 ret = setsockopt(socket, SOL_SOCKET, SO_KEEPALIVE, (char*)&keep_alive, sizeof(keep_alive)); 9 10 if (ret == SOCKET_ERROR) 11 { 12 printf("setsockopt failed: %d \n", WSAGetLastError()); 13 return -1; 14 } 15 16 struct tcp_keepalive in_keep_alive = {0}; 17 unsigned long ul_in_len = sizeof(struct tcp_keepalive); 18 struct tcp_keepalive out_keep_alive = {0}; 19 unsigned long ul_out_len = sizeof(struct tcp_keepalive); 20 unsigned long ul_bytes_return = 0; 21 22 in_keep_alive.onoff = 1; /*打開keepalive*/ 23 in_keep_alive.keepaliveinterval = 5000; /*發送keepalive心跳時間間隔-單位為毫秒*/ 24 in_keep_alive.keepalivetime = 1000; /*多長時間沒有報文開始發送keepalive心跳包-單位為毫秒*/ 25 26 ret = WSAIoctl(socket, SIO_KEEPALIVE_VALS, (LPVOID)&in_keep_alive, ul_in_len, 27 (LPVOID)&out_keep_alive, ul_out_len, &ul_bytes_return, NULL, NULL); 28 29 if (ret == SOCKET_ERROR) 30 { 31 printf("WSAIoctl failed: %d \n", WSAGetLastError()); 32 return -1; 33 } 34 35 return 0; 36 }