我遇到了一个很大的问题,即在运行Windows XP,Vista和8.1的客户端PC上保持持续的套接字连接在多个无线互联网提供商上工作。
我想要发生的事情:客户端PC从串行端口上的传感器读取数据,然后通过以太网/ IP将传感器消息发送到服务器。当互联网连接中断时,我的客户端应用程序会识别此情况并尝试建立新连接。这需要一天24小时自动发生。串行传感器每秒输出一次数据信息。我需要这些数据按时存储和延迟。
发生了什么:一切顺利,直到互联网连接被多次或一段时间内断开。客户端尝试创建新连接。经过一段时间或短时间无线断开连接只需几个小时后,客户端就可以打开任何端口。最终,Windows会重置所有端口,并且大部分时间都可以再次使用,具体取决于无线互联网。显然,Windows操作系统会在本地PC时钟下午12点左右重置端口,因为所有非功能性远程客户端突然能够在此时间点连接回服务器。
我发现:我的第一次尝试允许操作系统找到要使用的第一个可用的用户套接字端口号。经过很长一段时间运行一个有不良登录信息的客户端,所以它会被服务器重新命名并反复尝试,并观察netstat输出,我发现客户端将通过可用的端口号,直到系统的顶部端口号曾经为用户达成过。 Windows然后停止为客户端分配端口以使用,直到当天晚些时候操作系统重置所有端口。 所以我尝试了不同的东西。我使用bind将客户端锁定到特定端口。使用netstat验证它似乎工作,但最终我有相同的操作系统问题。我不知道该怎么做才能让它变得更好。我已将注册表设置为TcpTimedWaitDelay = 1秒。
这是我现在正在尝试的基本代码。每个阶段都有来自此函数的返回错误。
int check;
if(Socket != INVALID_SOCKET) //if not closed then close socket
{
closesocket(Socket);
Socket = INVALID_SOCKET;
}
time_f timer = getTimePrecise();
//wait 5 second before reconnect attempt
while(getTimePrecise() - timer < 5.0){}
//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;
ZeroMemory(&hints2, sizeof(hints2));
hints2.ai_family = AF_INET; //use IPv4
hints2.ai_socktype = SOCK_STREAM;
hints2.ai_protocol = IPPROTO_TCP;
hints2.ai_flags = AI_PASSIVE;
check = getaddrinfo(serverADDR , serverPORT, &hints2, &outbound);
check = getaddrinfo(NULL , DEFAULT_PORT, &hints, &local);
Socket = socket( local->ai_family, local->ai_socktype, local->ai_protocol);
check = bind(Socket, local->ai_addr, (int)local->ai_addrlen);
check = ioctlsocket(Socket, FIONBIO, &NonBlock);
char value = 0;
check = setsockopt( Socket, SOL_SOCKET, SO_DONTLINGER, &value, sizeof( value ) );
value = 1;
check = setsockopt( Socket, IPPROTO_TCP, TCP_NODELAY, &value, sizeof( value ) );
cout << "attempting connect" << endl;
check = connect(Socket, outbound->ai_addr, outbound->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(local);
freeaddrinfo(outbound);
return false;
}
else
{
if(FD_ISSET(Socket, &Write) )
{
freeaddrinfo(local);
freeaddrinfo(outbound);
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(local);
freeaddrinfo(outbound);
return false;
}
}
}
else if(check == WSAECONNREFUSED)
{
cout << "no server program at requested address " << serverADDR << endl;
closesocket(Socket);
freeaddrinfo(local);
freeaddrinfo(outbound);
return false;
}
else if(check == WSAEHOSTDOWN || check == WSAETIMEDOUT)
{
cout << "no server present at requested address " << serverADDR << endl;
closesocket(Socket);
freeaddrinfo(local);
freeaddrinfo(outbound);
return false;
}
else
{
cout << "connect call WSA error code " << check << endl;
closesocket(Socket);
freeaddrinfo(local);
freeaddrinfo(outbound);
return false;
}
}//end socket error
//else instant connection is good
cout << "socket opened to server instantly" << endl;
freeaddrinfo(local);
freeaddrinfo(outbound);
return true;
我想添加它以确定它是否会有所帮助。
value = 1;
check = setsockopt( Socket, IPPROTO_TCP, SO_REUSEADDR, &value, sizeof( value ) );
非常感谢任何帮助!
答案 0 :(得分:0)
无线技术是不可靠的。我总是设置一个计时器,如果在我定义的时间间隔内没有收到任何数据,我将终止套接字并尝试重新连接。每次读取时接收到的字节的简单计数器用于指示没有接收到数据.....启动计时器,如果在您的prdefined间隔中没有收到更多数据....关闭并重新启动套接字。或者切换到UDP。