【问题标题】:Identify network down on tcp socket using TCP_KEEPALIVE in C在 C 中使用 TCP_KEEPALIVE 识别 tcp 套接字上的网络关闭
【发布时间】:2014-07-19 12:52:30
【问题描述】:

我正在编写一个从 tcp 服务器接收数据的 tcp 客户端程序。当网络变坏(即网络中断)时,我无法关闭连接。

我使用 SO_KEEPALIVE 来允许应用程序为套接字连接启用保持活动数据包。 SO_KEEPALIVE 属性打开成功,但我无法修改 KeepAliveTime 的默认值(即 2 小时)

编辑 KeepAliveTime 的另一个可用选项是编辑注册表值,但我在 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters 位置找不到注册表项

以下代码检查并启用 SO_KEEPALIVE。

char optval;
char optout;
int optlen;
int optlen2;
optlen = sizeof(optval);
optlen2 = sizeof(optout);
got = getsockopt(loFds[i], SOL_SOCKET, SO_KEEPALIVE, &optval, &optlen );
if(got < 0) 
{
    printf("getsockopt unsuccessful. Error %ld\n", WSAGetLastError());
}
else if (got == 0)  {
//printf("SO_KEEPALIVE is %s\n", (optval ? "ON" : "OFF"));
printf("SO_KEEPALIVE is %ld\n", optval);
}


optval = 1;
//optout = 1;
got = (setsockopt(loFds[i], SOL_SOCKET, SO_KEEPALIVE, &optval, optlen));
 if( got < 0) 
 {
    printf("setsockopt unsuccessful on socket\n");
 }
 else if (got == 0)  {
     printf("SO_KEEPALIVE set on socket\n");
 }



got = (getsockopt(loFds[i], SOL_SOCKET, SO_KEEPALIVE, &optout, &optlen2 ));
if( got < 0) 
{

    printf("getsockopt unsuccessful. Error %ld\n", WSAGetLastError());

}
else if (got == 0)  {
    printf("SO_KEEPALIVE is %ld\n", optval);
}

但我要求它在用户定义的时间(可能是 5 分钟左右)后断开套接字。请提出任何其他解决方案。

平台:Windows 7 Professional 上的 Visual C 2012

【问题讨论】:

  • 你能在应用层做吗?也就是说,使用你自己的“心跳”消息来知道连接是否断开?
  • 您的代码检查了两次。为什么?
  • @JohnZwinck 我不确定如何使用我自己的心跳消息,因为它是一个多线程应用程序并同时连接多个套接字。
  • @EJP 我想知道套接字的默认状态,因此我在启用它之前检查它

标签: c sockets visual-studio-2012 tcp tcpsocket


【解决方案1】:

在 Windows 2000 及更高版本上,您可以使用 WSAIoctl(SIO_KEEPALIVE_VALS) 而不是 setsockopt(SO_KEEPALIVE) 来设置基于每个套接字的自定义保持活动超时/间隔值。

您还可以在读取数据之前使用select()WSAAsyncSelect()WSAEventSelect() 检测数据何时可供读取。如果在数据到达之前发生超时,只需关闭套接字即可。

【讨论】:

  • @Remy..我之前尝试过使用 WSAIoctl() 但我的环境似乎无法识别该功能。你知道它为什么会这样吗?
  • @SIA: WSAIoctl()winsock2.h 中声明,而不是在winsock.h 中声明。而SIO_KEEPALIVE_VALSMstcpip.h 中声明。你在你的代码中#include'ing 那些头文件吗?并链接到Ws2_32.lib/Ws2_32.dll?
  • 是的,你是对的..我使用的是“winsock.h”而不是“winsock2.h”。我现在已经包含了“winsock2.h”,但我的代码给出了很多“结构类型重新定义”和“重新定义”;不同的链接错误。我现在正在弄清楚它们
  • 我已经排除了winsock.h 并包含了winsock2.h,但我似乎仍然得到'struct' type redefinition errors。知道为什么会这样吗?
  • winsock.h 和 winsock2.h 不共存。 Winsock2.h 替换了 winsock.h,但 windows.h 仍然包含 winsock.h,除非定义了 WIN32_LEAN_AND_MEAN。否则,您可以在 windows.h 之前包含 winsock2.h,或者在项目的全局定义中添加 _WINSOCKAPI_ 以禁用 winsock.h。
【解决方案2】:

全局定义:

struct tcp_keepalive alive;
DWORD dwBytesRet = 0;

Keep alive 实现从这里开始:

alive.onoff = TRUE;             //keepalive enabled
alive.keepaliveinterval = 1000; //Interval between keepalive probes is set to 1 sec

alive.keepalivetime = 20000;    //Keep alive time set to 20 sec

if (WSAIoctl(loFds[i], SIO_KEEPALIVE_VALS, &alive, sizeof(alive), NULL, 0,
&dwBytesRet, NULL, NULL) == SOCKET_ERROR)
{
    printf("WSAIotcl(SIO_KEEPALIVE_VALS) failed.\n");
}
else
{
    printf("WSAIotcl(SIO_KEEPALIVE_VALS) Success.\n");
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-04-03
    • 2011-04-20
    • 1970-01-01
    • 1970-01-01
    • 2018-09-24
    • 2011-01-26
    • 2015-12-07
    • 1970-01-01
    相关资源
    最近更新 更多