【问题标题】:Is it correct to put a Winsocket connect() and send() in a loop?将 Winsock connect() 和 send() 放在一个循环中是否正确?
【发布时间】: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


    【解决方案1】:

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

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

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

    【讨论】:

    • 感谢您的回答。我不需要检查网络服务器状态。我只需要知道目标是否已连接。在您看来,connect() 是否足够?我想避免在目标完全可达时 connect() 返回错误的误报情况。此外,您认为当前的实现(每次创建和销毁套接字)是正确的吗?当操作系统出现时会发生什么。将分配临时端口 65536?它会从较低的端口正确重启还是挂起?谢谢:)
    • 我真的不明白如何从真正的错误中识别错误的连接错误。我能想象的唯一方法是忽略前几个错误并仅在达到某个阈值时报告问题。连接成功后,无论如何 send 都不会返回错误,只有 web 服务器立即关闭连接。至于端口空间耗尽 - 不要忘记清理你的套接字,系统会很好。每秒一个连接的负载非常低,可以轻松处理。
    猜你喜欢
    • 2011-09-13
    • 2015-12-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多