我正在开发一个Windows远程客户端程序,它通过以太网/互联网连接将数据从传感器单元发送到服务器应用程序。客户端使用用户名和密码登录服务器。根据协议,客户端然后以一种方式将数据发送到服务器,而不期望服务器的响应。一切正常,直到客户端的无线互联网连接断开。在我的第一个版本的客户端中,我重新尝试连接每个循环,但经常会因为Windows标准超时为4分钟而耗尽端口。我前几天尝试更换一个客户端。我将Windows注册表设置为“TcpTimedWaitDelay”为1并重写了客户端应用程序以在出错时关闭其套接字然后等待1秒再尝试重新连接。这似乎有效,但今天我确实松了那个客户端。我无法确定无线网络是否一直处于脱机状态。 我正在寻找有关使用可靠使用的此类客户端的好方法的建议。是否有其他方法可以防止应用程序代码中的端口耗尽或几乎总是需要修改Windows注册表?我可以添加我的代码片段,但我已经在最近的问题中查看了我的代码本身。我在这里寻找更广泛的建议。
void checkConnect(NTRIP& server)
{
time_f functionTime = getTimePrecise();
//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
{
cout << "received " << recvBytes << " bytes of data" << endl;
}
}
if(FD_ISSET(server.socket, &Err))
{
cout << "ip thread select returned socket in error group" << endl;
closesocket(server.socket); //what if dont close this socket, leave open for another loop
server.connected_IP = false;
}
}
else if(iResult == SOCKET_ERROR)
{
cout << "ip thread select returned SOCKET_ERROR " << WSAGetLastError() << endl;
closesocket(server.socket);
server.connected_IP = false;
}
//2nd check hard disconnect
if(server.connected_IP == true && functionTime - timer_send_keepalive >= 15.0)
{
timer_send_keepalive = functionTime;
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;
}
else if(lasterror != WSAEWOULDBLOCK)
{
cout << "server testing connection send function error " << lasterror << endl;
closesocket(server.socket);
server.connected_IP = false;
}
}
else
{
cout << "sent out keep alive " << iResult << " bytes" << endl;
}
}//end send keep alive
}
发送功能
bool sendData(CHAR_MESSAGE& data)
{
bool check = false;
if(data.flag_toSend == true)
{
if(WaitForSingleObject(data.mutex, 0) != WAIT_FAILED)
{
if(server_main.connected_IP == true)
{
int iResult = send(server_main.socket, data.buffer, data.bufferLength, 0);
if(iResult == SOCKET_ERROR)
{
int lasterror = WSAGetLastError();
if(lasterror == WSAEWOULDBLOCK)
{
cout << "main server send WSAEWOULDBLOCK" << endl;
check = false;
}
if(lasterror != WSAEWOULDBLOCK)
{
cout << "server main send error " << lasterror << endl;
closesocket(server_main.socket);
server_main.connected_IP = false;
check = false;
}
}
else
{
check = true;
server_main.lastDataSendTime = getTimePrecise();
//{cout << "sent data to main server" << endl;}
}
}
if(server_backup.connected_IP == true)
{
int iResult = send(server_backup.socket, data.buffer, data.bufferLength, 0);
if(iResult == SOCKET_ERROR)
{
int lasterror = WSAGetLastError();
if(lasterror == WSAEWOULDBLOCK)
{
cout << "backup server send WSAEWOULDBLOCK" << endl;
//check = false;
}
if(lasterror != WSAEWOULDBLOCK)
{
cout << "server backup send error " << lasterror << endl;
closesocket(server_backup.socket);
server_backup.connected_IP = false;
}
}
else
{
server_backup.lastDataSendTime = getTimePrecise();
//{cout << "sent data to backup server" << endl;}
}
}
data.flag_toSend = false;
ReleaseMutex(data.mutex);
}//end obtained mutex
}//end data flag to send is true
return check;
}
登录功能
bool loginServer(NTRIP& datasource )
{
std::string sLogin = buildLogin(datasource);
char databuf[1030];
int iResult = send(datasource.socket, sLogin.c_str(), sLogin.length(), 0);
if(iResult == SOCKET_ERROR)
{
cout << "Send error = " << WSAGetLastError() << endl;
closesocket(datasource.socket);
return false;
}
else //not socket error
{
int flags = 0;
fd_set Read, Err;
TIMEVAL Timeout;
FD_ZERO(&Read);
FD_ZERO(&Err);
FD_SET(datasource.socket, &Read);
FD_SET(datasource.socket, &Err);
Timeout.tv_sec = 1;
Timeout.tv_usec = 0;
iResult = select(0, &Read, NULL, &Err, &Timeout);
if(iResult == 0)
{
cout << "loginServer function, select timeout" << endl;
closesocket(datasource.socket);
return false;
}
else if(FD_ISSET(datasource.socket, &Read) )
{
int recvBytes = recv(datasource.socket, databuf, sizeof(databuf), flags);
if(recvBytes == SOCKET_ERROR)
{
cout << "loginServer function, Error recv call " << WSAGetLastError() << endl;
closesocket(datasource.socket);
return false;
}
else if(recvBytes == 0) //server closed connection
{
cout << "loginServer function, server reclosed connection" << endl;
closesocket(datasource.socket);
return false;
}
else if(recvBytes > 0) //process response
{
std::string tempString;
for(int n=0; n<recvBytes; n++)
{
tempString += databuf[n];
}
if(tempString.compare(CONNECT_OK) || tempString.compare(HTTP_OK) )
{
cout << "server connected" << endl;
return true;
}
else if(tempString.compare(ERROR_1))
{
MessageBox(NULL, ERROR_1, "NTRIP connect Error", MB_OK);
closesocket(datasource.socket);
return false;
}
else if(tempString.compare(ERROR_2))
{
MessageBox(NULL, ERROR_2, "NTRIP connect Error", MB_OK);
closesocket(datasource.socket);
return false;
}
else if(tempString.compare(ERROR_3))
{
MessageBox(NULL, ERROR_3, "NTRIP connect Error", MB_OK);
closesocket(datasource.socket);
return false;
}
else if(tempString.compare(ERROR_4))
{
MessageBox(NULL, ERROR_4, "NTRIP connect Error", MB_OK);
closesocket(datasource.socket);
return false;
}
}
}
else if(FD_ISSET(socket, &Err) )
{
cout << "loginServer function, select call error" << endl;
closesocket(datasource.socket);
return false;
}
}//end not socket error on send login
closesocket(datasource.socket);
return false;
}
打开一个新的套接字
bool clientOpenSocket_connectServer(SOCKET& Socket, const char* serverADDR, const char* serverPORT)
{
int check;
if(Socket != INVALID_SOCKET) //if not closed then close socket
{
closesocket(Socket);
Socket = INVALID_SOCKET;
}
time_f timer = getTimePrecise();
while(getTimePrecise() - timer < 5.0){} //wait 5 second before reconnect attempt
//set Windows reg to 1 second TcpTimedWaitDelay
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET; //use IPv4
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;
//get socket memory address info
check = getaddrinfo(serverADDR , serverPORT, &hints, &result);
if ( check != 0)
{
printf("Winsock getaddrinfo failed. %d\n", WSAGetLastError());
return false;
}
//prepare socket, sets IP4 or IP6, sock type and protocol used
for(ptr=result; ptr!=NULL; ptr=ptr->ai_next)
{
Socket = socket( result->ai_family, result->ai_socktype, result->ai_protocol);
if (Socket == INVALID_SOCKET)
{
printf("Socket failed initializing %d %d.\n", Socket, WSAGetLastError());
freeaddrinfo (result);
return false;
}
//now have a valid socket
check = ioctlsocket(Socket, FIONBIO, &NonBlock);
if (check == SOCKET_ERROR)
{
printf("client socket could not set nonblocking, with error: %d\n", WSAGetLastError());
closesocket(Socket);
freeaddrinfo(result);
return false;
}
//set sockets to no-linger on close
char value = 0;
check = setsockopt( Socket, SOL_SOCKET, SO_DONTLINGER, &value, sizeof( value ) );
if (check == SOCKET_ERROR)
{
cout << "client socket could not set options no-linger " << WSAGetLastError() << endl;
}
//disable nagle algorithym
if(disableNagleSockets == true)
{
value = 1;
check = setsockopt( Socket, IPPROTO_TCP, TCP_NODELAY, &value, sizeof( value ) );
if (check == SOCKET_ERROR)
{
cout << "client socket could not set options " << WSAGetLastError() << endl;
}
else{cout << "Nagle Sockets set disabled" << endl;}
value = 0;
check = setsockopt( Socket, IPPROTO_TCP, SO_SNDBUF, &value, sizeof( value ) );
if (check == SOCKET_ERROR)
{
cout << "client socket could not set options " << WSAGetLastError() << endl;
}
}
//attempt connect
cout << "attempting connect" << endl;
check = connect(Socket, ptr->ai_addr, ptr->ai_addrlen);
if(check == SOCKET_ERROR )
{
check = WSAGetLastError();
if(check == WSAEWOULDBLOCK) // then set a timeout
{
fd_set Write, Err;
TIMEVAL Timeout;
int TimeoutSec = 10; // timeout after 10 seconds
FD_ZERO(&Write);
FD_ZERO(&Err);
FD_SET(Socket, &Write);
FD_SET(Socket, &Err);
Timeout.tv_sec = TimeoutSec;
Timeout.tv_usec = 0;
check = select(0, NULL, &Write, &Err, &Timeout);
if(check == 0)
{
printf("connect call to server, select call timeout elapsed\r\n");
closesocket(Socket);
freeaddrinfo(result);
return false;
}
else
{
if(FD_ISSET(Socket, &Write) )
{
freeaddrinfo(result);
cout << "socket opened to server, after wait" << endl;
return true;
}
if(FD_ISSET(Socket, &Err) )
{
printf("connect call to server, select call error state\r\n");
closesocket(Socket);
freeaddrinfo(result);
return false;
}
}
}
else if(check == WSAECONNREFUSED)
{
cout << "no server program at requested address " << serverADDR << endl;
closesocket(Socket);
freeaddrinfo(result);
return false;
}
else if(check == WSAEHOSTDOWN || check == WSAETIMEDOUT)
{
cout << "no server present at requested address " << serverADDR << endl;
closesocket(Socket);
freeaddrinfo(result);
return false;
}
else
{
cout << "connect call WSA error code " << check << endl;
closesocket(Socket);
freeaddrinfo(result);
return false;
}
}//end socket error
//else instant connection is good
cout << "socket opened to server" << endl;
freeaddrinfo(result);
return true;
}//end search for a socket address to use
freeaddrinfo(result); //no socket opened here
return false;
}//end of setup TCP port
到目前为止,它在尝试另一个连接之前等待最后一次失败的连接5秒钟。我的早期版本尝试了每个循环的新连接,直到它连接。现在似乎它可能正在使用5秒延迟并设置Windows注册表以在1秒后关闭端口。
答案 0 :(得分:1)
使用连接直到它断开,然后创建另一个连接。
如果经常中断您遇到端口耗尽,则会出现网络问题,而不是编程问题。
如果出现连接错误,您应该在每次失败时休眠一段时间,例如: 1,2,4,8,...秒。