connect(),select(),recv()

Автор mihail_1, 01 сентября 2013, 21:02:28

« назад - далее »

0 Пользователи и 1 гость просматривают эту тему.

mihail_1

Программа на Си открывает соединение по 80 порту, отправляет запрос и получает ответ. После открытия сокета вызовом connect(), делаю его неблокирующим (чтобы самому контролировать timeout) и получаю данные вызывая recv(), пока он не вернет 0 (или не истечет timeout). Получаю много лишней загрузки процессора. Поэтому перед вызовом recv() поставил вызов select() указав ему сокет и timeout.
          FD_ZERO(&set_select);
          FD_SET(sock,&set_select);
          tv_select.tv_sec=15;
          tv_select.tv_usec=0;
          if(select(1,&set_select,NULL,NULL,&tv_select)!=0)
          {
             recv();
          }
Почему-то select() не замечает появления данных для чтения и всегда завершается по timeout.

smallNix

У тебя при этом errno, случаем не равно EWOULDBLOCK? Если так, то попробуй всё-таки сокет оставить блокируемым
Ты проверяшь только нулевой дескриптор?
Можешь попробовать использовать функцию poll вместо select
Для отладки вместо последнего аргумента подсунь в select 0 - тогда ожидание должно стать вечным до готовности.
Ну и как обычно - удостоверься, что событие происходит, а то, может, не тот порт или не тот дескриптор ;)
Кто-то же должен что-то делать...

mihail_1

Действительно ошибся с первым аргументом, взяв его из примера.
Теперь работает.
Только осталась проблема с концом данных. Без select recv всегда возвращал 0 при конце данных, а как определять теперь?


smallNix

 Мне незнакома функция recv(), а вот recvfrom - другое дело. Она, должна, по идее возвращать длину данных (а не 0), либо "-1" в случае неудачи. При этом errno содержит код ошибки.
P.S.: Прости что долго отвечал - засмотрелся сериалом. )))  ::)
Кто-то же должен что-то делать...

mihail_1

recv() возращает длинну если данные есть, 0 если конец данных, -1 если ошибка.
Но похоже при использовании select конец данных иногда теряется (что возвращает select при конце данных в документации не нашел).

smallNix

#5
Возвращаемые значения функции select:
0  - Истекло время таймера, а готовых дескрипторов нет
-1 - Возникла ошибка
Значение больше 0 - количество готовых дескрипторов

В POSIX ввели функцию pselect. Помимо неё можешь воспользоваться, как я уже говорил, функцией poll

Сообщение объединено: 03 сентября 2013, 01:31:07

А ты не под старый UNIX программу пишешь? Например под SVR4? Там в функции select была ошибка. Проверь свою систему на соответствие стандарту.
Кто-то же должен что-то делать...

mihail_1

Описанный в документации возвращаемые select() значения я прочитал, но из этого не ясно что он вернет когда recv() должен вернуть 0 и почему при использовании select(), recv() не всегда успевает вернуть 0 (сразу возвращает -1).
Можно ли вызывать recv() select()вернул ошибку и считать возврат -1 также признаком конца данных?

pselect() позволяет отслеживать дополнительно и сигналы (что не нужно)
poll() делает похоже тоже самое, только данные передаются в него в другом формате.

Линукс debian, версия этого года.

smallNix

 Я тебе предложил попробовать pselect или  poll на тот случай если ты считаешь, что проблема в функции select. С другой стороны, select возвращает количество готовых дескрипторов. У неё не должно быть особого поведения на случай конца файла. Я бы искал проблему в recv(). Попробуй использовать recvfrom. Кроме того, убедись, что всё делаешь правильно. Если select вернул -1 - см. значение errno. Но будет некорректно и глупо надеяться использовать recv, потому что ты не знаешь есть ли доступные дескрипторы. Можешь запросто получить аварийный останов. Следует чётко разделять назначения функций.   ;)
Кто-то же должен что-то делать...

mihail_1

Я не считаю, что какая-то из функций работает не так как должна, просто я не знаю как отлавливать конец данных при использовании recv() с select().

А за что это я могу получить аварийный останов? (Я ведь могу вызывать recv() вообще не вызывая select())

smallNix

Да, но ты должен вызывать для существующего дескриптора, а никак иначе. Хотя, допускаю, что всё может ограничится просто установкой errno. Но, по-хорошему, нельзя обращаться к несуществующему дескриптору. Мне трудно анализировать дальше - не хватает данных. Попробуй дать побольше информации о том какие значения ты ожидаешь и какие получаешь.
Кто-то же должен что-то делать...

mihail_1

А куда может дескриптор деться, пока я его не закрою?

Ну а какие данные еще нужны? Открываю соединение. По HTTP запрашиваю данные. Хочу получить все данные посланные в ответ и закрыть соединение. В заголовке ответа не всегда приситствует длинна, поэтому нужно использовать признак конца данных. Чтобы не ждать слишком долго нужен timeout. И нужно чтобы мимнимально грузился процессор.

smallNix

mihail_1, я прошу прощения, но меня не будет в сети около недели или двух - напряжённая работа. Если вопрос будет актуален, то я по возвращению в реальность попробую помочь, поэтому, по возможности, обозначьте статус проблемы.
P.S.: Прости за задержку - реальная жизнь требует. :-[
Кто-то же должен что-то делать...