It creates almost 900 threads
Это частично ваша проблема. Каждый поток, скорее всего, использует 1 МБ стека по умолчанию. Вы начинаете приближаться к ГБ потока потока. Шансы на нехватку памяти высоки. Весь смысл использования IOCP заключается в том, что вам не нужно создавать «поток на соединение». Вы можете просто создать несколько потоков (от 1x до 4x числа процессоров), чтобы прослушивать обработчик порта завершения и каждый поток обслуживать свой запрос для максимизации масштабируемости.
Я вспоминаю, как читал статью, связанную с переполнением стека, в которой буферы, которые вы публикуете для ожидающих операций IOCP, настроены таким образом, что операционная система НЕ позволит памяти поменяться с физической памяти на диск. И тогда вы можете исчерпать системные ресурсы, когда количество подключений станет большим.
Обходной путь, если я правильно помню, состоит в том, чтобы отправить 0-байтовый буфер (или это был 1-байтовый буфер) для каждого подключения к сокету. Когда поступят данные, ваш обработчик порта завершения вернется, и это подсказка вашему коду для размещения большего буфера. Если я смогу найти ссылку, я поделюсь ею.