Позвольте мне добавить префикс, сказав, что я никогда не использовал порты завершения ввода / вывода, хотя слышал о них уже много лет. Мой фон в первую очередь с select
, poll
, epoll
, а также WSAEventSelect
в сочетании с WaitForMulitpleObjects
, Пожалуйста, исправьте меня, если у меня есть фундаментальное неправильное понимание портов завершения ввода / вывода в следующем тексте.
Как часть проекта на работе, мне поручено разработать плагин (DLL) для симуляции, который позволяет клиенту подключаться к плагину и отправлять / получать данные в / из симуляции через TCP. Плагин действует как сервер. Имитация моделирует каналы связи другого (не Ethernet) интерфейса, и имеет смысл иметь один сокет на канал в этом конкретном приложении. Я не знаю, сколько клиентов будет, или сколько каналов (сокетов) будет открыто каждым клиентом. Тем не менее, я знаю, что вполне возможно, что их будет более 64, и что это не будет необычайно большое число, вероятно, не более тысячи.
Важным аспектом моделирования является то, что плагин может делать работу только тогда, когда его test_cycle
функция называется. Во время каждого цикла испытаний мне необходимо:
Поскольку может быть более 64 сокетов, я не могу (легко) использовать WSAEventSelect
а также WSAWaitForMultipleEvents
проверить, можно ли читать сокет или клиент корректно разорвал соединение.
Поэтому я подумал о двух других способах сделать это.
Пусть каждый сокет будет неблокирующим. Каждый раз test_cycle
вызывается, перебирая все сокеты, пытаясь получить до максимального количества данных на сокет.
Используйте порт завершения ввода / вывода и выполните асинхронный прием от сокетов. В test_cycle
, неоднократно звоните GetQueuedCompletionStatus
с dwMilliseconds
параметр установлен в 0
, пока не истечет время ожидания (WAIT_TIMEOUT
?). Если происходит прием, отложите следующий прием до конца цикла тестирования, чтобы клиент, рассылающий сообщения на сервер, не вызывал у нас бесконечный цикл test_cycle
(с надеждой).
Интерфейс для симуляции не является поточно-ориентированным, и для пересылки данных в симуляцию требуется совсем немного обработки, поэтому я не думаю, что было бы полезно иметь рабочие потоки для порта завершения ввода / вывода , что бы просто сделать блокировку и вызвать API моделирования. Однако отсутствие опроса каждого сокета может привести к повышению производительности.
Таким образом, для такого масштаба применения, максимум менее 1000 сокетов и, как правило, менее 100, есть ли реальная выгода для дополнительной сложности использования портов завершения ввода / вывода?
Я думаю, что вы могли бы сделать это:
1) Создайте поток слушателя. Для каждого соединения отправляет копию сокета в пул потоков;
2) создать пул потоков для обработки запросов;
Я использую канал для передачи между потоками без использования портов завершения ввода / вывода, и производительность является исключительной.
Установите контрольные пределы, чтобы гарантировать, что ресурсы не истощаются.