Во-первых, я должен спросить, что является лучшим, в каком состоянии? Например, сервер MMORPG в режиме реального времени. Что делать, если я создаю поток для каждого клиента вместо использования неблокирующих сокетов? Или что, если я использую один поток, содержащий все неблокирующие сокеты? Можете ли вы объяснить мне преимущества?
Почему я должен использовать неблокирующие или блокирующие сокеты?
Ответ 1
Ваш вопрос заслуживает гораздо более продолжительного обсуждения, но здесь короткий удар по ответу:
- с использованием блокирующих сокетов означает, что только один сокет может быть активен в любой момент в любом одном потоке (поскольку он блокирует при ожидании активности)
- Использование блокирующих сокетов обычно проще, чем неблокирующие сокеты (асинхронное программирование имеет тенденцию быть более сложным).
- вы могли бы создать 1 поток на один сокет, как вы заявили, но потоки имеют накладные расходы и крайне неэффективны по сравнению с неблокирующими решениями;
- с неблокирующими сокетами вы можете обрабатывать гораздо больший объем клиентов: он может масштабироваться до сотен тысяч в одном процессе, но код становится немного сложнее.
С неблокирующими сокетами (в Windows) у вас есть несколько вариантов:
- опрос
- события на основе
- перекрытие ввода/вывода
Overlapped I/O даст вам лучшую производительность (тысячи сокетов/процессов) за счет того, что это самая сложная модель для правильного понимания и реализации.
В основном это сводится к производительности и сложности программирования.
ПРИМЕЧАНИЕ
Здесь лучшее объяснение того, почему использование модели thread/socket - плохая идея:
В Windows создание большого количества потоков крайне неэффективно, поскольку планировщик не может правильно определить, какие потоки должны получать процессорное время, а какие нет. Это в сочетании с издержками памяти для каждого потока означает, что у вас закончится нехватка памяти (из-за пространства стека) и процессорных циклов (из-за накладных расходов на управление потоками) на уровне ОС задолго до того, как у вас не будет возможности обрабатывать соединения сокетов.
Ответ 2
Я буду говорить, говоря, что почти для всех, кроме игрушечных программ, вы должны использовать неблокирующие сокеты, как само собой разумеющееся.
Блокирующие сокеты вызывают серьезную проблему: если компьютер с другого конца (или любая часть вашего соединения с ним) не работает во время блокирующего вызова, ваш код будет заблокирован до истечения времени ожидания IP-стека. В типичном случае это около 2 минут, что совершенно неприемлемо для большинства целей. Единственный способ 1 прервать этот блокирующий вызов - это прекратить поток, который его создал, но завершение потока само по себе почти всегда неприемлемо, поскольку по существу невозможно его очистить и вернуть все ресурсы был выделен. Неблокирующие сокеты делают тривиальным прерывание вызова, когда/если это необходимо, без каких-либо действий с потоком, который совершил вызов.
Возможно, блокирующие сокеты работают хорошо, если вместо этого вы используете модель с несколькими процессами. Здесь вы просто создаете совершенно новый процесс для каждого соединения. Этот процесс использует блокирующий сокет, и когда/если что-то пойдет не так, вы просто убиваете весь процесс. ОС знает, как очистить ресурсы от процесса, поэтому очистка не является проблемой. У него все еще есть другие потенциальные проблемы: 1) вам в значительной степени нужен монитор процессов, чтобы убивать процессы, когда это необходимо, и 2) нерестование процесса, как правило, довольно дорого, чем просто создание сокета. Тем не менее, это может быть жизнеспособным вариантом, особенно если:
- Вы имеете дело с небольшим количеством подключений за раз
- Как правило, вы выполняете обширную обработку для каждого соединения.
- Вы имеете дело только с локальными хостами, поэтому ваше соединение с ними выполняется быстро и надежно
- Вы больше озабочены оптимизацией разработки, чем выполнением
1. Ну, технически не единственный возможный способ, но большинство альтернатив относительно уродливы - чтобы быть более конкретным, я думаю, что к тому времени, когда вы добавите код, чтобы понять, что есть проблема, а затем исправить проблему, вы, вероятно, сделали больше дополнительной работы, чем если бы вы использовали неблокирующий сокет.