【发布时间】:2011-09-29 23:48:21
【问题描述】:
我想弄清楚我正在编写的这个应用程序是否有问题。
该应用程序的目标是检测连接在同一 LAN 上的嵌入式设备是否断开连接。我在 stackoverflow 上阅读了很多关于这个问题的常见问题。
由于此嵌入式设备在默认端口上运行了一个网络服务器,因此其想法是创建一个无限循环并在该端口上持续发送消息。如果我检测到错误,我假设主机已断开连接。
然而,经过大量研究、局域网上的数据包嗅探等,我发现将send() 置于无限循环中与第一次调用它时不同。
原因是当你创建一个套接字并第一次调用发送时,它会执行TCP HANDSHAKE,然后发送消息。但是,在同一个循环中,当再次调用 send 时,没有 HANDSHAKE 并且消息被简单发送。因此,如果我此时断开嵌入式设备,发送将再次成功返回,并且只有在多次尝试后才会失败。 recv() 也发生了类似的情况。
所以我的实际解决方案是在套接字(creation,connection,send,destruction) 的整个过程中放入一个无限循环。这是我最后做的:
while(true){
SOCKET ConnectSocket = INVALID_SOCKET;
ConnectSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (ConnectSocket == INVALID_SOCKET) {
cout <<"socket failed with error: "<< WSAGetLastError();
WSACleanup();
return 0;
}
iResult= ioctlsocket(ConnectSocket,FIONBIO,&ulMode);
if (iResult != NO_ERROR)
cout<<"ioctlsocket failed with error: "<<iResult<<endl;
iResult= setsockopt(ConnectSocket,SOL_SOCKET,SO_REUSEADDR,(char *) &bOptVal,bOptLen);
if (iResult == SOCKET_ERROR) {
wprintf(L"setsockopt for SO_REUSEADDR failed with error: %u\n", WSAGetLastError());
closesocket(ConnectSocket);
WSACleanup();
} else
wprintf(L"Set SO_REUSEADDR: ON\n");
iResult= setsockopt(ConnectSocket,SOL_SOCKET, SO_LINGER, (char FAR*)&linger, sizeof(linger));
if (iResult == SOCKET_ERROR) {
wprintf(L"setsockopt for SO_LINGER failed with error: %u\n", WSAGetLastError());
closesocket(ConnectSocket);
WSACleanup();
} else
wprintf(L"Set SO_LINGER: ON\n");
if(connect( ConnectSocket,(SOCKADDR*) &saServer, sizeof(saServer))==SOCKET_ERROR){
cout <<WSAGetLastError()<<endl;
if(WSAGetLastError() == WSAEWOULDBLOCK)
{
fd_set fsConnect;
FD_ZERO(&fsConnect);
FD_SET(ConnectSocket, &fsConnect);
timeval sTimeoutVal;
sTimeoutVal.tv_sec = (long)2;
sTimeoutVal.tv_usec = (long)0;
int retval = select(FD_SETSIZE, (fd_set *) NULL, &fsConnect, (fd_set *)
NULL, &sTimeoutVal);
if(retval != 1)
{
closesocket(ConnectSocket);
WSACleanup();
return 1;
}
} else{
closesocket(ConnectSocket);
WSACleanup();
return 1;
}
}
int iBytes = send(ConnectSocket, sendbuf, (int)strlen(sendbuf), 0);
shutdown(ConnectSocket,SD_SEND);
closesocket(ConnectSocket);
if(iBytes == -1 || iBytes != (int)strlen(sendbuf))
{
//send failed machine went down
WSACleanup();
return 1;
}
Sleep(1000);}
基本上该程序运行良好。因为它每秒迭代一次,所以我不知道它在操作系统中是否真的正确。透视因为我不知道这样我做错了什么。
此外,我注意到许多打开的端口仍处于 TIME_WAIT 状态,因此我每次将套接字标记为 SO_REUSEADDR 和 SO_LINGER。在运行此应用程序 3/4 小时后,我有大约 200 个开放端口及时等待。
这是对的吗?我应该遵循另一种可能更简单的方法吗?
谢谢大家! ;)
【问题讨论】:
标签: c++ windows sockets winsock