【问题标题】:not getting a Winsock error when ethernet unplugged拔下以太网时未收到 Winsock 错误
【发布时间】:2015-11-08 22:28:13
【问题描述】:

我正在开发一个客户端应用程序,它以一种方式将传感器数据发送到远程服务器。初次登录后,服务器没有返回数据。我的问题是当以太网断开连接时,例如硬断开连接,即无线链路断开,我的应用程序在尝试“发送”调用后没有得到错误返回值。我正在使用单个非阻塞套接字实例。线程使用'select'检查每个循环的'recv'。它最终会在“recv”上出现错误,但在“send”上不会出现错误。 当远程 PC 出现 Internet 连接丢失时,它会导致程序与服务器断开连接数分钟到数小时,然后才能识别出连接丢失并切换到重新登录服务器。可以做些什么来帮助检测硬断开连接?

void checkConnect(NTRIP& server)
{
//1st check for recv or gracefully closed socket
char databuf[SERIAL_BUFFERSIZE];
fd_set Reader, Writer, Err;
TIMEVAL Timeout;
Timeout.tv_sec = 1; // timeout after 1 seconds
Timeout.tv_usec = 0;
FD_ZERO(&Reader);
FD_ZERO(&Err);
FD_SET(server.socket, &Reader);
FD_SET(server.socket, &Err);
int iResult = select(0, &Reader, NULL, &Err, &Timeout);
if(iResult > 0)
{
    if(FD_ISSET(server.socket, &Reader) )
    {
        int recvBytes = recv(server.socket, databuf, sizeof(databuf), 0);
        if(recvBytes == SOCKET_ERROR)
        {
            cout << "socket error on receive call from server " << WSAGetLastError() << endl;
            closesocket(server.socket);
            server.connected_IP = false;
        }
        else if(recvBytes == 0)
        {
            cout << "server closed the connection gracefully" << endl;
            closesocket(server.socket);
            server.connected_IP = false;
        }
        else  //>0 bytes were received so read data if needed
        {

        }
    }
    if(FD_ISSET(server.socket, &Err))
    {
        cout << "select returned socket in error state" << endl;
        closesocket(server.socket);
        server.connected_IP = false;
    }
}
else if(iResult == SOCKET_ERROR)
{
    cout << "ip thread select socket error " << WSAGetLastError() << endl;
    closesocket(server.socket);
    server.connected_IP = false;
}
//2nd check hard disconnect if no other data has been sent recently
if(server.connected_IP == true && getTimePrecise() - server.lastDataSendTime > 5.0)
{
    char buf1[] = "hello";
    cout << "checking send for error" << endl;
    iResult = send(server_main.socket, buf1, sizeof(buf1), 0);
    if(iResult == SOCKET_ERROR)
    {
        int lasterror = WSAGetLastError();
        if(lasterror == WSAEWOULDBLOCK)
        {
            cout << "server send WSAEWOULDBLOCK" << endl;
        }
        if(lasterror != WSAEWOULDBLOCK)
        {
            cout << "server testing connection send function error " << lasterror << endl;
            closesocket(server.socket);
            server.connected_IP = false;
        }
    }
    else
    {
        cout << "sent out " << iResult << " bytes" << endl;
    }

    server.lastDataSendTime = getTimePrecise();
}

}

【问题讨论】:

  • TCP 基于连接可靠的假设。这使得它非常非常高效,您可以转储一堆数据以使用 send() 进行传输,并且协议栈会尽其所能来交付该数据。后来,不要让你的程序陷入困境。您不必等待,直到收到“好的,它到了”确认。非常重要的是,延迟会杀死 perf dead。这当然意味着“它不再起作用”的消息也会延迟传递。在调用 shutdown() 之前,您无法确定。

标签: c++ sockets tcp-ip winsock2


【解决方案1】:

在您尝试发送内容之前,无法检测到断开连接。 您的解决方案如下:

  1. 您检测到您在一段时间内没有收到任何数据,您想检查连接是否处于活动状态。

  2. 您使用send 函数将一些数据发送到服务器。它可能是特定于协议的 ping 数据包或垃圾。 send 函数立即返回,因为它不等待实际数据发送。它只填充内部发送缓冲区。

  3. 您开始等待套接字读取。

  4. 在您等待时,操作系统会尝试将发送缓冲区中的数据发送到服务器。

  5. 当操作系统检测到它无法向服务器传递数据时,连接被标记为错误。

  6. 现在调用recvsend函数时会报错。

发送超时是系统特定的,可以配置。通常,大约是 20 秒 (Linux) - 2 分钟 (Windows)。这意味着您需要等待很长时间才能收到错误。

注意事项:

  1. 你也可以开启TCP keep alive机制,但我不建议你这样做。

  2. 您还可以修改 TCP 超时间隔。当您希望连接在临时网络断开连接后仍然存在时,它会很有帮助。

【讨论】:

    【解决方案2】:

    这就是 TCP 的工作方式,并且旨在发挥作用。您将在随后的发送中收到错误,但在断开连接后的第一次发送中绝不会出现错误。在发出错误信号之前,需要克服缓冲、重试和重试超时。

    【讨论】:

    • 我从来没有从发送函数中得到错误,无论是数据还是 5 秒的“hello”字符串,如果没有数据被发送,我会尝试得到错误。我只在 recv 函数上遇到错误。需要明确的是,如果 5 秒内没有发送传感器数据,则会发送“hello”消息以“测试”连接。这个测试仍然没有返回错误。
    • 您将在后续发送中收到与先前发送相关的错误。一个非常后续的发送。可能需要几分钟。
    猜你喜欢
    • 2022-12-13
    • 2010-10-20
    • 1970-01-01
    • 2018-11-24
    • 2012-04-25
    • 2018-07-06
    • 1970-01-01
    • 1970-01-01
    • 2019-08-19
    相关资源
    最近更新 更多