2

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

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处理函数,它也需要一分钟才能被调用。

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

我还尝试更改tldp.org上讨论的与 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 参数实际上是在几分钟内吗?我应该在代码中寻找可能影响此超时参数的某个函数吗?

4

3 回答 3

1

你最好的选择是应用层保持活动;也就是说,每 X 秒发送一个无操作 (NOP) 消息,并期望一个相当快的 NOP 确认 (NOP-ACK)。此外,如果您的远程连接关闭是“优雅的”,那么您send应该几乎立即解除阻塞。如果它不是优雅的(例如网络元素失败),那么您的应用层保持活动将在您下次 X+(预期响应时间)时检测到丢失...

于 2013-03-05T18:50:05.693 回答
1

TCP_KEEPCNT(自 Linux 2.4 起) TCP 在断开连接之前应发送的最大保活探测数。此选项不应在旨在可移植的代码中使用。

也许这就是原因。你可以在你的应用程序中实现你自己的保持活动,这应该很容易。如果没有应用程序数据或保持活动的“心跳”来,就开始戳另一端。

于 2013-03-05T18:59:45.097 回答
1

我可以通过该TCP_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 应用程序表明连接在大约 4 秒内断开(我想 3 表示等待时间,1 表示保持活动空闲)。

我也可以在代码中的单个套接字级别上更改它。在文件/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));

将具有与改变系统参数相同的效果。

我确实同意应用程序级保活确实是要走的路中的其他答案。而且,正如这里提到的,

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

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

于 2013-03-06T18:46:01.443 回答