Ожидание данных с помощью выбора не работает - PullRequest
3 голосов
/ 07 июня 2010

В настоящее время я работаю над проектом, который включает в себя несколько клиентов, подключенных к серверу и ожидающих данных. Я использую выбор и отслеживаю соединение для входящих данных. Однако клиент просто продолжает ничего не печатать, действуя так, как будто select обнаружил входящие данные. Возможно, я нападаю на это неправильно?

Для первого фрагмента данных, который сервер отправляет, он отображается правильно. Однако затем сервер отключается, и клиент продолжает извергать пустые строки.

        FD_ZERO(&readnet);
        FD_SET(sockfd, &readnet);   
while(1){

            rv = select(socketdescrip, &readnet, NULL, NULL, &timeout);
            if (rv == -1) {
                perror("select"); // error occurred in select()
            } else if (rv == 0) {
                printf("Connection timeout!  No data after 10 seconds.\n");
            } else {
                // one or both of the descriptors have data
                if (FD_ISSET(sockfd, &readnet)) {
                    numbytes = recv(sockfd, buf, sizeof buf, 0);
                    printf("Data Received\n");
                    buf[numbytes] = '\0';
                    printf("client: received '%s'\n",buf);
                    sleep(10);
                }
            }
        }

Ответы [ 5 ]

4 голосов
/ 07 июня 2010

Я думаю, вам нужно проверить результат recv. Если он возвращает ноль, я думаю, это означает, что сервер закрыл сокет.

Также (в зависимости от реализации) вам может потребоваться передать socketdescrip+1 в select.

2 голосов
/ 07 июня 2010

Если я правильно помню, вам нужно инициализировать набор fd с перед каждым вызовом select(), потому что select() повреждает его.

Так что перемещайте FD_ZERO() и FD_SET() внутри цикланезадолго до select().

1 голос
/ 27 августа 2013

Когда сервер закрывает соединение, он отправляет пакет с флагом FIN на сторону клиента, чтобы объявить, что он больше не отправляет данные. Пакет обрабатывается стеком TCP / IP на стороне клиента и не имеет данных для уровня приложения. Уровень приложения уведомляется о срабатывании выбора, потому что что-то произошло в дескрипторе отслеживаемого файла, и recv () возвращает 0 байтов, поскольку данные не отправляются сервером.

1 голос
/ 08 июня 2010

действует так, как будто выбор обнаружил входящие данные. Возможно я атакую это неправильно?

В дополнение к тому, что было сказано ранее, я хотел бы отметить, что select () / poll () не говорит вам, когда «данные есть», а скорее, что следующий соответствующий системный вызов не будет блокироваться. Вот и все. Как было сказано выше, recv () не блокирует и правильно возвращает 0, что означает EOF, соединение было закрыто другой стороной.

Хотя в большинстве * nix систем в этом случае только первый вызов recv () вернул бы 0, последующие вызовы вернут -1. При использовании асинхронного ввода-вывода обязательна тщательная проверка ошибок!

И лично я настоятельно рекомендую использовать poll () вместо этого. В отличие от select (), он не уничтожает свои аргументы и отлично работает с дескрипторами сокетов с высоким номером.

0 голосов
/ 08 июня 2010

Верно ли это, когда речь идет о вашем коде?

select(highest_file_descriptor+1, &readnet, NULL, NULL, &timeout);

В вашем простом примере (с перемещением FD_ZERO и FD_SET внутри цикла while (1), как сказал qrdl), оно должно выглядеть так:

select(sockfd+1, &readnet, NULL, NULL, &timeout);

Также обратите внимание, что когда recv возвращает 0 байт, это означает, что соединение было закрыто - больше никаких данных!Ваш код также содержит ошибки - когда в recv происходит что-то плохое (когда это происходит, возвращается <0), у вас будут серьезные проблемы, потому что что-то вроде buf [-1] может привести к непредсказуемым результатам.Пожалуйста, обработайте этот случай правильно. </p>

Хотя я уважаю тот факт, что вы пытаетесь использовать низкоуровневый API сокетов BSD, я должен сказать, что я нахожу его ужасно неэффективным.Вот почему я рекомендую вам, если возможно, использовать ACE , который является очень эффективной и продуктивной средой, в которой уже реализовано множество вещей, когда речь идет о сетевом программировании (например, ACE_Reactor - это то, что облегчаетделать то, что вы пытаетесь достичь здесь).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...