Вопрос

while (xxx) {
    timeout.tv_sec=TIMEOUT;
    timeout.tv_usec=0;
    FD_ZERO(&set); 
    FD_SET(sd,&set);

    switch (select(FD_SETSIZE,&set,NULL,NULL,&timeout))
    xxxxx
}

работает нормально, однако

FD_ZERO(&set); 
FD_SET(sd,&set);

while (xxx) {
    timeout.tv_sec=TIMEOUT;
    timeout.tv_usec=0;

    switch (select(FD_SETSIZE,&set,NULL,NULL,&timeout))
    xxxxx
}

нет.Это работает в первый раз, но в следующий раз, когда он проходит через цикл while, он получает тайм-аут, даже если сокет SD получает данные.Мне кажется, что каждый раз очищать и заполнять набор — это пустая трата ресурсов.

У кого-нибудь есть хорошее объяснение, почему это так, а еще лучше, возможно, предложение, как этого избежать?

Это было полезно?

Решение

select изменяет свои аргументы.Вам действительно придется каждый раз заново инициализировать его.

Если вас беспокоят накладные расходы, то стоимость обработки полного FD_SET в ядре несколько более значительна, чем стоимость FD_ZERO.Вам нужно передать только максимальный fd, а не FD_SETSZIZE, чтобы минимизировать обработку ядра.В вашем примере:

switch (select((sd + 1),&set,NULL,NULL,&timeout))

В более сложном случае с несколькими fds вы обычно сохраняете переменную max:

FD_SET(sd,&set);
if (sd > max) max = sd;
... repeat many times...

switch (select((max + 1),&set,NULL,NULL,&timeout))


Если у вас будет большое количество файловых дескрипторов и вы обеспокоены накладными расходами на их перемещение, вам следует рассмотреть некоторые альтернативы select().Вы не указываете, какую ОС используете, но для Unix-подобных ОС их несколько:

  • для Linux — epoll()
  • для FreeBSD/NetBSD/OpenBSD/MacOS X, kqueue()
  • для Solaris: /dev/poll

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

Другие советы

Прочтите справочную страницу выбора.Возвращаемый набор — это только файловые дескрипторы, готовые к использованию.Вы должны использовать FD_ISSET для проверки каждого из них, установлен он или нет.

Всегда инициализируйте fd_set непосредственно перед его использованием.

Именно так работает select.Лучше всего это работает и имеет больше смысла, если у вас более одного сокета.В этом и суть:вы выбираете множество сокетов.Если вы хотите читать из одного сокета, просто прочитайте или получите его.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top