将Winsocket connect()和send()放入循环中是否正确?

Is it correct to put a Winsocket connect() and send() in a loop?

本文关键字:是否 循环 connect Winsocket send      更新时间:2023-10-16

我想弄清楚我正在编写的这个应用程序是否有问题。
该应用程序的目标是检测连接在同一局域网上的嵌入式设备是否断开连接。一个常见的问题,我在这里读了很多关于stackoverflow。
由于这个嵌入式设备在默认端口上运行一个web服务器,因此我们的想法是创建一个无限循环,并在该端口上不断发送消息。如果我检测到一个错误,我假设主机已断开连接。
然而,经过大量的研究,局域网上的数据包嗅探等,我发现将send()置于无限循环中与您第一次调用它不同。
原因是当您创建套接字并第一次调用send时,它执行TCP HANDSHAKE,然后发送消息。但是,在同一个循环中,当send再次被调用时,没有握手,消息只是被发送。因此,如果我在这一刻断开嵌入式设备,发送将再次返回成功,只有在几次尝试后才会失败。类似的情况也发生在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: %un", WSAGetLastError());
                    closesocket(ConnectSocket);
                                        WSACleanup();
               } else
                    wprintf(L"Set SO_REUSEADDR: ONn");
            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: %un", WSAGetLastError());
                             closesocket(ConnectSocket);
                                                WSACleanup();
                            } else
                                wprintf(L"Set SO_LINGER: ONn");

           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个开放端口。
对吗?我应该遵循另一种更简单的方法吗?感谢所有!div;)

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

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

TIME_WAIT是ok,这是正常状态,这个状态会逐渐超时。