在运行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 ) );任何帮助都将不胜感激!
发布于 2015-11-24 14:25:15
无线的问题是它是不可靠的。我总是设置一个计时器,如果在我定义的时间间隔内没有接收到数据,我将终止套接字并尝试重新连接。每次读取时接收到的字节数的简单计数器表示没有数据received.....start计时器,如果在预定义的interval....close中没有接收到更多数据,则重新启动套接字。或者切换到UDP。
https://stackoverflow.com/questions/33854868
复制相似问题