Linux下Tcp保活时间默认多少,C/C++网络编程中的TCP保活
在默認(rèn)的情況下,TCP連接是沒有保活的心跳的。這就是說,當(dāng)一個TCP的socket,客戶端與服務(wù)端誰也不發(fā)送數(shù)據(jù),會一直保持著連接。這其中如果有一方異常掉線,另一端永遠(yuǎn)也不可能知道。這對于一些服務(wù)型的程序來說,將是災(zāi)難性的后果。
所以,必須對創(chuàng)建的socket,啟用保活心跳,即Keepalive選項。
啟用Keepalive
對于WIN32或者Linux平臺來說,設(shè)置socket的Keepalive都很簡單,只需使用setsockopt設(shè)置SO_KEEPALIVE即可。
setsockopt的函數(shù)原型在Linux環(huán)境下為:[cpp]#include?
#include?
intsetsockopt(ints,intlevel,intoptname,
constvoid*optval,
socklen_t?optlen);,在WIN32平臺下為 [cpp]#include?
intsetsockopt(ints,intlevel,intoptname,
constchar*optval,
intoptlen);
因為const void *可以接受const char *型的參數(shù),所以為了代碼的跨平臺編譯考慮,可以采用以下代碼來設(shè)置TCP的Keepalive選項。[cpp]alive?=?1;
if(setsockopt
(fd,?SOL_SOCKET,?SO_KEEPALIVE,?(constchar*)?&alive,
sizeofalive)?!=?0)
{
log_warn?("Set?keep?alive?error:?%s.\n",?strerror?(errno));
return-1;
}
這樣,對于TCP的連接,就啟用了系統(tǒng)默認(rèn)值的保活心跳。
Linux環(huán)境下的TCP Keepalive參數(shù)設(shè)置
為什么說是系統(tǒng)默認(rèn)值的呢?因為有這樣幾個值,我們并沒有手動設(shè)置,是采用的系統(tǒng)默認(rèn)值。即,
多長時間發(fā)送一次保活心跳?
如果沒有返回,多長時間再重試發(fā)送?
重試幾次為失敗?
如果是Linux操作系統(tǒng),這三個值分別為[plain]#?cat?/proc/sys/net/ipv4/tcp_keepalive_time
7200
#?cat?/proc/sys/net/ipv4/tcp_keepalive_intvl
75
#?cat?/proc/sys/net/ipv4/tcp_keepalive_probes
9
這就是說,在Linux系統(tǒng)下,如果對于TCP的socket啟用了Keepalive選項,則會在7200秒(即兩個小時)沒有數(shù)據(jù)后,發(fā)起KEEPALIVE報文。如果沒有回應(yīng),則會在75秒后再次重試。如果重試9次均失敗,則認(rèn)定連接已經(jīng)失效。TCP的讀取操作,將返回0。
這對于我們大多數(shù)應(yīng)用來說,前兩個時間值都有點太長了。
我們可以通過重設(shè)上面三個值,來使得操作系統(tǒng)上運(yùn)行的所有啟用了Keepalive選項的TCP的socket的行為更改。
我們也可以只針對我們自己創(chuàng)建的socket,重設(shè)這三個值。它們分別對應(yīng)TCP_KEEPIDLE、TCP_KEEPINTL和TCP_KEEPCNT的選項值,同樣可以使用setsockopt進(jìn)行設(shè)置。[cpp]#include?
#include?
#include?
#include?
#include?
#include?
#include?
#include?
int
socket_set_keepalive?(intfd)
{
intret,?error,?flag,?alive,?idle,?cnt,?intv;
/*?Set:?use?keepalive?on?fd?*/
alive?=?1;
if(setsockopt
(fd,?SOL_SOCKET,?SO_KEEPALIVE,?&alive,
sizeofalive)?!=?0)
{
log_warn?("Set?keepalive?error:?%s.\n",?strerror?(errno));
return-1;
}
/*?10秒鐘無數(shù)據(jù),觸發(fā)保活機(jī)制,發(fā)送保活包?*/
idle?=?10;
if(setsockopt?(fd,?SOL_TCP,?TCP_KEEPIDLE,?&idle,sizeofidle)?!=?0)
{
log_warn?("Set?keepalive?idle?error:?%s.\n",?strerror?(errno));
return-1;
}
/*?如果沒有收到回應(yīng),則5秒鐘后重發(fā)保活包?*/
intv?=?5;
if(setsockopt?(fd,?SOL_TCP,?TCP_KEEPINTVL,?&intv,sizeofintv)?!=?0)
{
log_warn?("Set?keepalive?intv?error:?%s.\n",?strerror?(errno));
return-1;
}
/*?連續(xù)3次沒收到保活包,視為連接失效?*/
cnt?=?3;
if(setsockopt?(fd,?SOL_TCP,?TCP_KEEPCNT,?&cnt,sizeofcnt)?!=?0)
{
log_warn?("Set?keepalive?cnt?error:?%s.\n",?strerror?(errno));
return-1;
}
return0;
}
WIN32環(huán)境下的TCP Keepalive參數(shù)設(shè)置
而WIN32環(huán)境下的參數(shù)設(shè)置,就要麻煩一些,需要使用另外的一個函數(shù)WSAIoctl和一個結(jié)構(gòu)struct tcp_keepalive。
它們的原型分別為:[cpp]#include?
#include?
intWSAIoctl(
SOCKET?s,
DWORDdwIoControlCode,
LPVOIDlpvInBuffer,
DWORDcbInBuffer,
LPVOIDlpvOutBuffer,
DWORDcbOutBuffer,
LPDWORDlpcbBytesReturned,
LPWSAOVERLAPPED?lpOverlapped,
LPWSAOVERLAPPED_COMPLETION?lpCompletionRoutine
);
structtcp_keepalive?{
u_long?onoff;
u_long?keepalivetime;
u_long?keepaliveinterval;
};
在這里,使用WSAIoctl的時候,dwIoControlCode要使用SIO_KEEPALIVE_VALS,lpvOutBuffer用不上,cbOutBuffer必須設(shè)置為0。
struct tcp_keepalive結(jié)構(gòu)的參數(shù)意義為:
onoff,是否開啟KEEPALIVE; keepalivetime,多長時間觸發(fā)Keepalive報文的發(fā)送; keepaliveinterval,多長時間沒有回應(yīng)觸發(fā)下一次發(fā)送。
注意:這里兩個時間單位都是毫秒而不是秒。[cpp]#include?
#include?
int
socket_set_keepalive?(intfd)
{
structtcp_keepalive?kavars[1]?=?{
1,
10?*?1000,/*?10?seconds?*/
5?*?1000/*?5?seconds?*/
};
/*?Set:?use?keepalive?on?fd?*/
alive?=?1;
if(setsockopt
(fd,?SOL_SOCKET,?SO_KEEPALIVE,?(constchar*)?&alive,
sizeofalive)?!=?0)
{
log_warn?("Set?keep?alive?error:?%s.\n",?strerror?(errno));
return-1;
}
if(WSAIoctl
(fd,?SIO_KEEPALIVE_VALS,?kavars,sizeofkavars,?NULL,sizeof(int),?&ret,?NULL,
NULL)?!=?0)
{
log_warn?("Set?keep?alive?error:?%s.\n",?strerror?(WSAGetLastError?()));
return-1;
}
return0;
}
總結(jié)
以上是生活随笔為你收集整理的Linux下Tcp保活时间默认多少,C/C++网络编程中的TCP保活的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux到不了启动界面,Linux 界
- 下一篇: linux 其他常用命令