0

Почему стоит использовать неблокирующие или Blocking-сокеты? [закрыто]

16

Проблема: Неясный вопрос о потоках и сокетах в MMORPG на StackOverflow

Я столкнулся с вопросом относительно проектирования многопользовательского MMORPG-сервера и нуждаюсь в помощи. Вот что меня интересует:

  1. Какой подход является лучшим? Использовать отдельный поток для каждого клиента или создать один поток, который будет обрабатывать все неблокирующие сокеты?
  2. Каковы преимущества и недостатки каждого из этих подходов?

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

2 ответ(ов)

0

Ваш вопрос заслуживает более детального обсуждения, но вот краткий ответ:

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

При использовании неблокирующих сокетов (в Windows) у вас есть несколько вариантов:

  • опрос (polling)
  • на основе событий (event-based)
  • перекрытый ввод-вывод (overlapped I/O)

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

В конечном счете, дело сводится к производительности против сложности программирования.

ПРИМЕЧАНИЕ

Вот лучшее объяснение, почему использование модели потоков/сокетов — плохая идея:

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

0

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

Блокирующие сокеты создают серьезные проблемы: если машина на другом конце (или любая часть вашего соединения с ней) недоступна во время блокирующего вызова, ваш код будет заблокирован до тех пор, пока не произойдет тайм-аут стека IP, который в типичном случае составляет около 2 минут — это совершенно неприемлемо для большинства задач. Единственный способ1 прервать блокирующий вызов — завершить поток, который его выполнил, но завершение потока само по себе почти всегда неприемлемо, так как это практически невозможно сделать безопасно и вернуть ресурсы, которые он выделил. Неблокирующие сокеты позволяют легко прерывать вызов, когда это необходимо, без каких-либо действий с потоком, который его инициировал.

Можно заставить блокирующие сокеты работать более-менее приемлемо если вы используете многопроцессную модель. Здесь вы просто создаете совершенно новый процесс для каждого соединения. Этот процесс использует блокирующий сокет, и когда/если что-то идет не так, вы просто убиваете весь процесс. Операционная система умеет очищать ресурсы процесса, поэтому проблемы с очисткой не возникает. Тем не менее, это может иметь и другие потенциальные проблемы: 1) вам практически нужен монитор процессов для завершения процессов при необходимости, и 2) создание нового процесса обычно стоит значительно дороже, чем просто создание сокета. Тем не менее, это может быть жизнеспособным вариантом, особенно если:

  1. Вы имеете дело с небольшим количеством соединений одновременно
  2. Вы, как правило, проводите обширную обработку для каждого соединения
  3. Вы работаете только с локальными хостами, поэтому ваше соединение с ними быстрое и надежное
  4. Вас больше беспокоит оптимизация разработки, чем выполнение

^1. Технически это не единственный способ, но большинство альтернатив относительно неудобны — если быть более конкретным, то к тому времени, как вы добавите код для определения проблемы и затем исправите её, вы, вероятно, сделаете больше работы, чем если просто используете неблокирующий сокет.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь