拔下以太网时没有得到Winsock错误

not getting a Winsock error when ethernet unplugged

本文关键字:Winsock 错误 以太网      更新时间:2023-10-16

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

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();
}

}

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

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

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

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

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

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

  6. 现在,调用recvsend函数时会出现错误。

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

注:

  1. 您也可以打开TCP保持活动机制,但我不建议您这样做。

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

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