C++ Keepalive time(保持有效时间)-在C+中不能减少到一分钟以下+;

C++ Keepalive time(保持有效时间)-在C+中不能减少到一分钟以下+;,c++,tcp,keep-alive,C++,Tcp,Keep Alive,我在C++应用程序中实现了一个KeaPoT时间,它通过下面的代码写入TCP端口。它没有显示,但我实际上检查了有效的返回状态,以验证设置选项是否有效 int option = 1; int keepalive_intvl = 1; int keepalive_count = 1; int keepalive_idle = 1; setsockopt(the_socket, SOL_SOCKET, SO_KEEPALIVE, &option, sizeof (int) ); setsock

我在C++应用程序中实现了一个KeaPoT时间,它通过下面的代码写入TCP端口。它没有显示,但我实际上检查了有效的返回状态,以验证设置选项是否有效

int option = 1;
int keepalive_intvl = 1;
int keepalive_count = 1;
int keepalive_idle = 1;

setsockopt(the_socket, SOL_SOCKET, SO_KEEPALIVE, &option, sizeof (int) );
setsockopt(the_socket, SOL_TCP, TCP_KEEPINTVL, &keepalive_intvl, sizeof(int));
setsockopt(the_socket, SOL_TCP, TCP_KEEPCNT, &keepalive_count, sizeof(int));
setsockopt(the_socket, SOL_TCP, TCP_KEEPIDLE, &keepalive_idle, sizeof(int));
我的应用程序正在写入TCP端口,并且每秒尝试写入几次

// write null packet to determine if connection is still good
return ( send( GetDescriptor(),(char*)NULL, 0, 0 ) != -1 );
根据上面的测试,每当我关闭另一个输入连接时,我的应用程序都会花费一分钟的时间报告连接已断开。如果我有一个
SIGPIPE
handler函数,那么调用它也需要一分钟

我看到的每个文档都表明keepalive参数是以秒为单位的,而不是以分钟为单位的。但我无法在一分钟内检测到断开的连接

我还尝试更改与上讨论的keepalive相关的系统变量,但没有效果

echo 1 > /proc/sys/net/ipv4/tcp_keepalive_time
echo 1 > /proc/sys/net/ipv4/tcp_keepalive_intvl
echo 1 > /proc/sys/net/ipv4/tcp_keepalive_probes

此行为是否由另一个系统参数控制?与某些文档相反,keepalive参数是否以分钟为单位?我应该在代码中寻找某个函数来影响这个超时参数吗?

你最好的选择是应用层保持活动状态;也就是说,每X秒发送一条无操作(NOP)消息,并期望合理快速的NOP确认(NOP-ACK)。此外,如果您的远程连接关闭“正常”,那么您的
发送应该几乎立即解除阻塞。如果不正常(例如,某个网元出现故障),那么您的应用程序层keep alive将在下一次X+(预期响应时间)检测到丢失

TCP_keepnt(从Linux 2.4开始) TCP在断开连接之前应发送的keepalive探测器的最大数量。此选项不应用于可移植的代码中


也许这就是原因。您可以在应用程序中实现自己的keep alive,这应该很容易。如果没有应用程序数据或“心跳”持续,只需开始拨动另一端。

我可以通过
TCP\u LINGER2
值更改总的持续时间

每当我关闭输入tcp进程时,我都使用
netstat-an
获取以下行

tcp        1      0 127.0.0.1:32962         127.0.0.1:7780          CLOSE_WAIT  
tcp        0      0 127.0.0.1:7780          127.0.0.1:32962         FIN_WAIT2  
我可以用两种不同的方式更改此
FIN_WAIT2
时间

在系统级,根据这一点,我可以通过修改系统文件来更改它,如下所示:

% cat /proc/sys/net/ipv4/tcp_fin_timeout
60

[To change this to 3 seconds]
# echo "3" > /proc/sys/net/ipv4/tcp_fin_timeout
我的输出TCP应用程序表明连接在大约四秒钟内断开(我想象3表示等待时间,1表示keepalive空闲时间)

我还可以在代码中的单个套接字级别上更改它。在文件
/usr/include/netinet/tcp.h
中,我看到了以下内容

#define TCP_LINGER2  8  /* Life time of orphaned FIN-WAIT-2 state */
因此,在我的代码中添加以下内容

int wait_time = 3;
setsockopt(the_socket, SOL_TCP, TCP_LINGER2, &wait_time,sizeof(int));
将产生与改变系统参数相同的影响

我确实同意其他答案,应用程序级别的keepalives确实是一条路要走。如前所述

RFC 1122第4.2.3.6节指出TCP的确认 没有数据的keepalives可能无法通过路由器可靠传输; 这可能会导致有效连接断开。此外,TCP/IP 堆栈根本不需要支持keepalive(而且很多 嵌入式堆栈不会),因此此解决方案可能无法转换为其他解决方案 平台


但是,在非测试环境中,我无法访问TCP输入,在该输入中我可以实现应用程序级keepalives的另一端,因此TCP keepalives可能是我的唯一选项。

选项是int而不是intint32@QuentinUK,它们在我的代码中是相同的。尽管如此,为了清晰起见进行了编辑。您是否尝试过实际检查
setsockopt()
的返回代码?如果您问我,用于检测连接丢失的Keepalive没有多大意义。这是不可靠的,充其量也是误导性的。保持有状态防火墙“温暖”或保持拨号链接连接是很有用的,但肯定不能确保连接处于活动状态。@AliAmiri:连接丢失根本不容易检测,因为底层协议(IP)不面向连接。通常,尝试发送时会很快出现错误(例如,如果另一端的服务器崩溃)。但是,很有可能只有几分钟后才会出现超时错误(例如,如果ICMP 3丢失)。不过,定期发送/接收并对错误代码作出反应是最好、最可靠的方法。如果我没记错的话,TCP keepalive默认每半小时发送一次,因此连接可能会在你不知道的情况下上下移动10次。任何类型的TCP应用层keepalive最终都肯定会有问题,它很难适应RTT、抖动、暂时失去连接等等。拥有两个时间关键层总是一个坏主意(因此隧道几乎总是使用UDP)。此外,您要将应用程序和keepalive数据混合在一个流中,这非常容易出错。当keep-alive处于秒级时,RTT和抖动可以忽略不计。如果TCP层没有处理暂时的连接丢失,那么应用程序必须处理这个问题。我同意,如果时间紧迫,TCP ACK施加的所有额外流量都会被浪费,UDP是一个更好的选择。问题是,我实际上无法访问另一端(另一个进程正在侦听)。我会在测试环境中这样做,但我不会总是这样。但是,是的,我同意,应用程序级keepalives将是我首选的方式。