Раздражающее поведение select () в c

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-сокет получает данные. Мне кажется пустой тратой ресурсов каждый раз опорожнять и заполнять сет.

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

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

SoapBox 13.11.2008 02:27
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
5
1
3 833
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

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

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

Я знаю о FD_ISSET, но я еще не включил его, потому что на данный момент я указываю только один сокет (позже я добавлю другие сокеты). Итак, теперь есть способ «повторно использовать» без предварительной установки fd_set?

deadcyclo 13.11.2008 02:53

Задокументированное поведение select () включает изменение наборов на месте. По словам Прагматичного программиста, «select не сломан».

bk1e 13.11.2008 06:44

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

Чтение не предлагает тайм-аут. Следовательно, использование select. + тот факт, что я добавлю второй сокет позже на стадии разработки.

deadcyclo 13.11.2008 02:54

Просто чтобы предлагать альтернативы: если sd - это сокет, вы можете использовать setsockopt (sd, SO_RCVTIMEO, ...), чтобы добавить таймаут чтения. Однако, если вы собираетесь добавить второй сокет позже, выберите лучший вариант.

DGentry 13.11.2008 22:58
Ответ принят как подходящий

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

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

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

В более сложном случае с несколькими fd вы обычно в конечном итоге поддерживаете максимальную переменную:

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 добавлен в набор, вы будете получать уведомления о событиях на этом fd без необходимости постоянно передавать его снова.

В качестве альтернативы select () почему бы не использовать poll (), который, в отличие от упомянутых вами, одинаков во многих Unix?

bortzmeyer 13.11.2008 15:47

poll () лучше тем, что вам не нужно каждый раз повторно инициализировать его массив, но вы по-прежнему копируете большую структуру в ядро ​​и из него при каждом вызове. Если у вас много fd, другие альтернативы позволяют избежать этих постоянных накладных расходов, изменяя набор fd в ядре.

DGentry 13.11.2008 17:03

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