Неблокирующая розетка с опросом - PullRequest
11 голосов
/ 29 июля 2010

Пару дней назад мне пришлось исследовать проблему, когда мое приложение показывало аномально высокую загрузку ЦП, когда оно (по-видимому) находилось в состоянии ожидания. Я отследил проблему до цикла, который должен был блокировать вызов recvfrom, пока сокет был установлен на O_NONBLOCK, что приводило к спин-блокировке. Было два способа решения проблемы: установить сокет на блокировку или опросить доступные данные на сокете, используя poll или select. Я выбрал первое, так как это было проще. Но мне интересно, почему кто-то может создать неблокирующий сокет, а затем опрашивать его отдельно. Разве блокирующий сокет не делает то же самое? В каких случаях можно использовать неблокирующую комбинацию сокета и опроса? Есть ли в этом какие-либо преимущества?

Ответы [ 4 ]

8 голосов
/ 29 июля 2010

Использование poll() или select() с неблокирующим файловым дескриптором дает вам два преимущества:

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

Если у вас есть только один файловый дескриптор (сокет) для ожидания, и вы не против ждать его бесконечно, тогда да; Вы можете просто использовать блокирующий вызов.

Вторым преимуществом действительно является случай использования убийцы для select() и друзей. Это означает, что вы можете обрабатывать несколько соединений сокетов, а также стандартный ввод и стандартный вывод и, возможно, файловый ввод-вывод, все с одним потоком управления.

2 голосов
/ 25 июля 2016

Я пишу здесь, потому что, хотя вопрос старый. Он как-то появился в моем поиске в Google и определенно не получил правильного ответа.

Принятый ответ лишь выдвигает на первый план два преимущества использования неблокирующих сокетов, но в действительности не углубляется в детали и не отвечает на реальный вопрос.

  • ПРИМЕЧАНИЕ. К сожалению, большинство онлайновых «учебных пособий» или фрагментов кода содержат только блокирующий код сокетов, поэтому знания о неблокирующих сокетах распространяются меньше.

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

Теперь я могу привести очень простой для понимания пример, и есть много других. Давайте возьмем пример игрового сервера. Игры развиваются в тиках, через регулярные промежутки времени, когда состояние игры изменяется, независимо от того, предоставляет игрок ввод (мышь / клавиатура) для изменения состояния игры. Теперь, когда сокеты вступают в игру в многопользовательских играх - если бы вы использовали блокирующие сокеты, состояние игры не улучшалось бы, если бы игроки не отправляли обновления - поэтому, если у них есть проблемы с интернетом, состояние игры никогда не будет постоянно обновляться и распространять изменения среди всех игроков , У вас был бы довольно изменчивый опыт.

Теперь, используя неблокирующие сокеты, вы можете запустить игровой сервер в однопоточном режиме, обновив состояние игры, а также сокеты, с ... скажем, интервалом тайм-аута 50 мс - и данные сокетов считываются только из подключенные пользователи, когда они действительно что-то отправляют, а затем подают на сервер симуляции, обрабатывают и подают в расчет состояния игры для следующего тика.

1 голос
/ 29 июля 2010

, приводящий к спин-блокировке.

Это условие обычно называется тугой петлей .

Было два способаРешение проблемы: установите сокет на блокировку или опрос для доступных данных на сокете, используя опрос или выберите.Я выбрал первый вариант, поскольку он был проще.

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

Иначе, тогда да, переключение в режим блокировки - самое простое решение.

Лучшее обратно-совместимое решение было бы до вызова recvfrom() для использования poll() чтобы дождаться, пока сокет станет читабельным.Этот способ гарантирует, что другие части кода будут работать точно так же, как и раньше.

Но мне интересно, почему кто-либо может создать неблокирующий сокет и затем опрашивать его отдельно.Разве блокирующая розетка не делает то же самое?

Для случая recvfrom() мне не известно никаких существенных отличий.

В каких случаях используютсябудет использовать неблокирующую комбинацию сокета и опроса?Есть ли в этом какие-либо преимущества?

Может быть простая ошибка кодирования.Или кто-то мог подумать, что возврат в тесном цикле как-то увеличит производительность.

0 голосов
/ 16 мая 2015

Всегда лучше создавать сокеты как nonblocking, потому что даже блокирующий сокет иногда переходит в состояние готовности (когда данные получены, но имеет ошибку контрольной суммы, и это отбрасывается) - даже когда нет данных для чтения.Так что сделайте это nonblocking, дождитесь доступности данных через опрос, затем прочитайте.Я думаю, что это главное преимущество.

...