Автор Тема: connect(),select(),recv()  (Прочитано 2741 раз)

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

Оффлайн mihail_1

  • Местный житель
  • ***
  • Сообщений: 169
connect(),select(),recv()
« : 01 Сентября 2013, 21:02:28 »
Программа на Си открывает соединение по 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

Re: connect(),select(),recv()
« Ответ #1 : 02 Сентября 2013, 01:51:09 »
У тебя при этом errno, случаем не равно EWOULDBLOCK? Если так, то попробуй всё-таки сокет оставить блокируемым
Ты проверяшь только нулевой дескриптор?
Можешь попробовать использовать функцию poll вместо select
Для отладки вместо последнего аргумента подсунь в select 0 - тогда ожидание должно стать вечным до готовности.
Ну и как обычно - удостоверься, что событие происходит, а то, может, не тот порт или не тот дескриптор ;)
Кто-то же должен что-то делать...
 

Оффлайн mihail_1

  • Местный житель
  • ***
  • Сообщений: 169
Re: connect(),select(),recv()
« Ответ #2 : 02 Сентября 2013, 11:37:25 »
Действительно ошибся с первым аргументом, взяв его из примера.
Теперь работает.
Только осталась проблема с концом данных. Без select recv всегда возвращал 0 при конце данных, а как определять теперь?

 

Оффлайн smallNix

Re: connect(),select(),recv()
« Ответ #3 : 02 Сентября 2013, 23:12:22 »
 Мне незнакома функция recv(), а вот recvfrom - другое дело. Она, должна, по идее возвращать длину данных (а не 0), либо "-1" в случае неудачи. При этом errno содержит код ошибки.
P.S.: Прости что долго отвечал - засмотрелся сериалом. )))  ::)
Кто-то же должен что-то делать...
 

Оффлайн mihail_1

  • Местный житель
  • ***
  • Сообщений: 169
Re: connect(),select(),recv()
« Ответ #4 : 03 Сентября 2013, 00:23:42 »
recv() возращает длинну если данные есть, 0 если конец данных, -1 если ошибка.
Но похоже при использовании select конец данных иногда теряется (что возвращает select при конце данных в документации не нашел).
 

Оффлайн smallNix

Re: connect(),select(),recv()
« Ответ #5 : 03 Сентября 2013, 01:29:12 »
Возвращаемые значения функции select:
0  - Истекло время таймера, а готовых дескрипторов нет
-1 - Возникла ошибка
Значение больше 0 - количество готовых дескрипторов

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

Сообщение объединено: 03 Сентября 2013, 01:31:07
А ты не под старый UNIX программу пишешь? Например под SVR4? Там в функции select была ошибка. Проверь свою систему на соответствие стандарту.
« Последнее редактирование: 03 Сентября 2013, 01:31:07 от smallNix »
Кто-то же должен что-то делать...
 

Оффлайн mihail_1

  • Местный житель
  • ***
  • Сообщений: 169
Re: connect(),select(),recv()
« Ответ #6 : 03 Сентября 2013, 12:18:29 »
Описанный в документации возвращаемые select() значения я прочитал, но из этого не ясно что он вернет когда recv() должен вернуть 0 и почему при использовании select(), recv() не всегда успевает вернуть 0 (сразу возвращает -1).
Можно ли вызывать recv() select()вернул ошибку и считать возврат -1 также признаком конца данных?

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

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

Оффлайн smallNix

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

Оффлайн mihail_1

  • Местный житель
  • ***
  • Сообщений: 169
Re: connect(),select(),recv()
« Ответ #8 : 04 Сентября 2013, 14:16:13 »
Я не считаю, что какая-то из функций работает не так как должна, просто я не знаю как отлавливать конец данных при использовании recv() с select().

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

Оффлайн smallNix

Re: connect(),select(),recv()
« Ответ #9 : 04 Сентября 2013, 17:22:44 »
Да, но ты должен вызывать для существующего дескриптора, а никак иначе. Хотя, допускаю, что всё может ограничится просто установкой errno. Но, по-хорошему, нельзя обращаться к несуществующему дескриптору. Мне трудно анализировать дальше - не хватает данных. Попробуй дать побольше информации о том какие значения ты ожидаешь и какие получаешь.
Кто-то же должен что-то делать...
 

Оффлайн mihail_1

  • Местный житель
  • ***
  • Сообщений: 169
Re: connect(),select(),recv()
« Ответ #10 : 05 Сентября 2013, 10:07:13 »
А куда может дескриптор деться, пока я его не закрою?

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

Оффлайн smallNix

Re: connect(),select(),recv()
« Ответ #11 : 08 Сентября 2013, 17:05:55 »
mihail_1, я прошу прощения, но меня не будет в сети около недели или двух - напряжённая работа. Если вопрос будет актуален, то я по возвращению в реальность попробую помочь, поэтому, по возможности, обозначьте статус проблемы.
P.S.: Прости за задержку - реальная жизнь требует. :-[
Кто-то же должен что-то делать...
 

Теги: