在循环中放置Winsocket connect()和send()是否正确?

时间:2011-09-29 15:02:35

标签: c++ windows sockets winsock

我正在试图弄清楚我正在编写的这个应用程序是否有问题 该应用程序的目标是检测连接在同一LAN上的嵌入式设备是否断开连接。我在stackoverflow上阅读了很多常见问题 由于此嵌入式设备具有在默认端口上运行的Web服务器,因此想法是创建无限循环并在该端口上连续发送消息。如果我检测到错误,我认为主机已断开连接 然而,经过大量研究,在局域网上嗅探数据包等,我发现将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);}

基本上程序运行正常。由于它每秒迭代一次,我不知道它是否真的从O.S.透视原因我不知道这种方式我做错了什么。
此外,我注意到很多开放端口仍处于TIME_WAIT状态,因此我每次将套接字标记为SO_REUSEADDR和SO_LINGER。运行此应用程序3/4小时后,我有〜200个开放端口及时等待 这是对的吗?我应该追随另一种,也许更简单的方式吗? 谢谢大家! ;)

1 个答案:

答案 0 :(得分:0)

如果您只检查Web服务器是否存在,则没有理由发送任何内容:仅使用connect()就足以确保目标至少在网络堆栈级别上存活。

为了更加确定目标状态,您可以从Web服务器中查询有用的内容并检查结果。如果服务器支持持久的HTTP连接,它将在服务器上稍微增加一些负载,但可以通过单一连接完成。在这种情况下你最好使用一些HTTP客户端库:正确实现客户端可能会很棘手。

TIME_WAIT没问题,这是正常状态,这种状态会逐渐超时。