... наиболее эффективно при проверке входящих данных (асинхронно).Допустим, у меня есть 500 соединений.У меня есть 3 сценария (о которых я могу думать):
Использование select () для одновременной проверки сокетов FD_SETSIZE, а затем итерация по всем из них для получения данных.(Разве для этого не требуется два вызова recv для каждого возвращаемого сокета? MSG_PEEK, чтобы выделить буфер, а затем снова выполнить recv (), который будет таким же, как # 3)
Надеюсь, вы внимательносоздание вашего набора fd только с теми дескрипторами, которые в данный момент подключены ...?Затем вы перебираете набор и запускаете recv () только для тех, которые имеют условия чтения или исключения / ошибки (последнее различие между реализациями BSD и Windows).Хотя функционально это нормально (и, возможно, концептуально элегантно), в большинстве реальных приложений вам не нужно заглядывать перед извлечением: даже если вы не уверены в размере сообщения и знаете, что можете посмотреть его из буфера, выследует подумать, можете ли вы:
- обработать сообщение порциями (например, прочитать любую хорошую единицу работы - может быть, 8k, обработать ее, а затем прочитать следующую <= 8k в тот же буфер ...)) </li>
- чтение в буфер, который достаточно велик для большинства / всех сообщений, и динамически распределяет больше, только если вы обнаружите, что сообщение неполное
Использование select () для проверкиодна розетка за раз.(Разве это не будет похоже на # 3? Требуется два вызова recv.)
Не очень хорошо.Если вы останетесь однопоточным, вам нужно будет установить значение 0 для тайм-аута на select и крутиться как сумасшедший в дескрипторах listenig и client.Очень бесполезно расходует процессорное время и значительно снижает задержку.
Используйте recv () с MSG_PEEK по одному сокету за раз, выделите буфер, затем снова вызовите recv ().Разве это не было бы лучше, потому что мы можем пропустить все вызовы select ()?Или издержки одного вызова recv () слишком велики?
(не обращая внимания на то, что лучше избегать MSG_PEEK) - как узнать, на каком сокете находится MSG_PEEK или recv ()?Опять же, если вы однопоточны, то вы либо заблокируете при первой попытке peek / recv, либо используете неблокирующий режим, а затем безумно крутите все дескрипторы, надеясь, что peek / recv что-нибудь вернет.Расточительно.
Итак, придерживайтесь 1 или переходите к многопоточной модели.Для последнего самый простой подход для начала - это заставить цикл прослушивающего потока вызывать accept, и каждый раз, когда accept принимает новый клиентский дескриптор, он должен порождать новый поток для обработки соединения.Эти потоки обработки клиентских соединений могут просто блокироваться в recv ().Таким образом, операционная система сама выполняет мониторинг и активацию потоков в ответ на события, и вы можете быть уверены, что это будет достаточно эффективно.Хотя эта модель звучит просто, вы должны знать, что многопоточное программирование имеет много других сложностей - если вы еще не знакомы с ней, вы, возможно, не захотите пытаться изучить это одновременно с сокетным вводом-выводом.