Стоит задача написать сервер, который поддерживал бы ~1000 подключений. Сервер прослушивает несколько портов. Не могу определиться с моделью ввода-вывода сокетов. Навязчиво преследует мысль сделать следующим образом: для прослушиваемых сокетов юзать WSAEvent, при подключении клиента запускать отдельный поток с обычным блокируемым сокетом. Теперь вопросы: 1) Засыпает ли поток при вызове recv для блокируемого сокета? То есть не тратится ли на него процессорного времени, пока он ожидает подключений? 2) Насколько вообще разумна такая модель? Есть ли серьезные причины, чтобы от нее отказаться? Читал, что порты завершения работают быстрее всего, но насколько велика разница и стоит ли она того, чтобы мучиться с этими портами?
Поток на recv блокирующего сокета конечно засыпает до получения заданного количества байт или ошибки/разрыва, время не ест. Но вот тысяча потоков - планировщик не подавится? Обычно заранее создают разумное количество потоков (до нескольких десятков), которые лежат в пуле и достаются оттуда по мере необходимости и возвращаются в пул, когда становятся не нужны. При ваших запросах однозначно есть смысл разобраться с портами завершения.
Кстати, есть еще вариант, WSA-нотификация - WSAAsyncSelect, виндовыми сообщениями окну. При определенной сноровке на нем вообще можно написать однопотоковый сервер.
Большое спасибо. Помогли. Вот только нагуглил, что потоков в пуле может быть лишь в два раза больше количества процессоров, а у вас до нескольких десятков. Как так?
Вопрос близкий по тематике: На сколько производительнее происходит работа с использованием "перекрытого" в\в против простых блокирующих сокетов ?
kevy Как вы понимаете "быстроту" ? Если вы под ней понимаете: 1) максимальная загрузка сервера полезной работой (а не простаиванием в ожидании "прихода миссии"); 2) экономия ресурсов на сервере (разумное число активных потоков). тогда вы должны смотреть в сторону Boost.Asio (лёгкий путь) или самому реализовать подобное с использованием IOCP.
Меня интересует сравнительная эффективность работы "перекрытого" в\в и блокирующих сокетов. WaitForMultipleObjects - а это не простаивание в ожидании "прихода мисии" ?! что именно будет экономиться ? я пока не знаком с внутренней реализацией "перекрытого" в\в, но подозреваю, что в плане выделения памяти экономия будет. нет, туда я смотреть не хочу, интересует именно сравнительная хар-ка описанного выше.
почитайте про epoll(саму архитектуру приложений, как организовывать). В винде что то подобное тоже быть должно.
Sholar 1) Нет не тратит.Sholar 2) Если только винда то юзай APC (Alertable thread + CompleteRoutine ) имхо это самое быстрое и экономное . Причем унифицираное для различных комуницация в том числе и для сокетов. Имхо int WSARecv( __in SOCKET s, __inout LPWSABUF lpBuffers, __in DWORD dwBufferCount, __out LPDWORD lpNumberOfBytesRecvd, __inout LPDWORD lpFlags, __in LPWSAOVERLAPPED lpOverlapped, __in LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine ); Сразу понятно что всякие поделки на подобие boost просто гуано быдло код, которые юзают гуано быдло кодеры. На одном потоки можно много, очень много конектов держать ... Но это все если руки не крюки и если ты не гуано быдло писатель для boost гуанно имплов.
shchetinin спасибо за ответ, но сразу вопрос - Alertable thread + CompleteRoutine это по сути такое же ожидание, как и при блокированном сокете, или я не прав ?
kevy Нет, вы можете ожидать : - Несколько сокетов - По таймоуту - Добавить event как сигнал для завершения(Или что вам захочется еще добавить ) - Легко довить любую другую комуникацию( Пайпы? ) Вы можете прервать ожидания, или же временно приостовить при доставки APC , ожидание останется(Ожидание это простой потока , так как реквест будет отправлен через стек к дрову и IRP будет свободен ) получается вы можете использовать квант потока более грамотно , чем быдло кодеры как то так.