Правильно ли поместить Winsocket connect () и send () в цикл? - PullRequest
0 голосов
/ 29 сентября 2011

Я пытаюсь выяснить, если я делаю что-то не так с этим приложением, я кодирую.Цель приложения - обнаружить, отключаются ли встроенные устройства, подключенные к той же локальной сети.Распространенная проблема, о которой я много читал здесь на stackoverflow.Поскольку у этого встроенного устройства есть веб-сервер, работающий на порте по умолчанию, идея состояла в том, чтобы создать бесконечный цикл и непрерывно отправлять сообщение на этот порт.Если я обнаружу ошибку, я предполагаю, что хост отключен.Однако после многих исследований, перехвата пакетов в локальной сети и т. Д. Я обнаружил, что помещение send() в бесконечный цикл не было таким же, как если бы вы вызывали его в первый раз.Причина в том, что когда вы создаете сокет и впервые вызываете 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.У меня ~ 200 открытых портов во времени ожидания после 3/4 часов работы этого приложения.Это правильно?Должен ли я следовать другим, может быть, более простым путем?Спасибо всем!;)

1 Ответ

0 голосов
/ 29 сентября 2011

Если вы просто проверяете существование веб-сервера, нет никакой причины отправлять что-либо: достаточно только connect (), чтобы убедиться, что цель жива, по крайней мере, на уровне сетевого стека.

Чтобы быть уверенным в целиСкажите, что вы можете спросить что-то полезное с веб-сервера и проверить результат.Это немного увеличит нагрузку на сервер, но может быть выполнено с помощью одного соединения, если сервер поддерживает постоянные соединения HTTP.В этом случае вам лучше использовать некоторую клиентскую библиотеку HTTP: правильная реализация клиентской стороны может быть сложной задачей.

TIME_WAIT в порядке, это нормальное состояние, и это состояние будет постепенно превышаться по времени.

...