拔掉以太网时没有出现 Winsock 错误
not getting a Winsock error when ethernet unplugged
我正在开发一个将传感器数据以一种方式发送到远程服务器的客户端应用程序。初始登录后,服务器没有 return 数据。我的问题是当以太网断开连接时,例如硬断开连接,即无线 link 出现故障,我的应用程序在尝试 'send' 调用后没有收到错误 return 值。我正在使用单个非阻塞套接字实例。线程使用 '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
函数向服务器发送了一些数据。它可能是特定于协议的 ping 数据包或垃圾。 send
函数 returns 立即生效,因为它不等待实际数据发送。它只填充内部发送缓冲区。
您开始等待套接字读取。
在您等待期间,OS尝试将发送缓冲区中的数据发送到服务器。
当OS检测到它无法向服务器传送数据时,连接被标记为错误。
现在调用recv
和send
函数时会报错
发送超时是系统特定的,可以配置。通常,大约是 20 秒 (Linux) - 2 分钟 (Windows)。这意味着您需要等待很长时间才能收到错误。
备注:
你也可以开启TCP keep alive机制,但我不建议你这样做
您还可以修改 TCP 超时间隔。当您希望连接在临时网络断开后仍然存在时,它会很有帮助。
我正在开发一个将传感器数据以一种方式发送到远程服务器的客户端应用程序。初始登录后,服务器没有 return 数据。我的问题是当以太网断开连接时,例如硬断开连接,即无线 link 出现故障,我的应用程序在尝试 'send' 调用后没有收到错误 return 值。我正在使用单个非阻塞套接字实例。线程使用 '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
函数向服务器发送了一些数据。它可能是特定于协议的 ping 数据包或垃圾。send
函数 returns 立即生效,因为它不等待实际数据发送。它只填充内部发送缓冲区。您开始等待套接字读取。
在您等待期间,OS尝试将发送缓冲区中的数据发送到服务器。
当OS检测到它无法向服务器传送数据时,连接被标记为错误。
现在调用
recv
和send
函数时会报错
发送超时是系统特定的,可以配置。通常,大约是 20 秒 (Linux) - 2 分钟 (Windows)。这意味着您需要等待很长时间才能收到错误。
备注:
你也可以开启TCP keep alive机制,但我不建议你这样做
您还可以修改 TCP 超时间隔。当您希望连接在临时网络断开后仍然存在时,它会很有帮助。