Странное поведение Winsock IOCP при потоке отключения - PullRequest
0 голосов
/ 15 октября 2018

Я программирую библиотеку Socket / Client / Server для C#, так как я много кросс-платформенного программирования, и я не нашел mono / dotnet / dotnet core достаточно эффективным ввысокопроизводительная обработка сокетов.

Sice linux epoll, несомненно, выиграл «борьбу» за производительность и удобство использования, я решил использовать интерфейс, подобный epoll, в качестве общего API, поэтому я пытаюсь эмулировать егов среде Windows (производительность сокета Windows для меня не так важна, как в Linux, но интерфейс такой) .Для этого я использую Winsock2 и Kernel32 API напрямую с Marshaling и использую IOCP.

Почти все работает нормально, кроме одного: когда я создаю сервер TCP с winsock и подключением к нему (с локального или с удаленного компьютера через локальную сеть, не имеет значения) с более чем 10000 подключениями, все подключения принимаются, вообще никаких проблем, когда все подключения отправляютсяданные (поток) со стороны клиента на сервер, вообще никаких проблем, сервер получает все пакеты, но когда я отключаю всех клиентов одновременно, сервер не распознает все события отключения (т. е. 0чтение байта / доступно), обычно 1500-8000 клиентов застряли .Событие завершения не запускается, поэтому я не могу обнаружить потерю соединения.

Сервер не падает, он продолжает принимать новые соединения, и все работает, как ожидалось, только потерянные соединения не делаютполучить распознавание .

Я читал это - потому что для использования overlapped IO требуется предварительно выделенный буфер чтения - IOCP при чтении блокирует эти буферы и освобождаетблокирует при завершении и , если в одно и то же время происходит слишком много событий , он не может заблокировать все затронутые буферы из-за ограничения ОС, и это вызывает IOCP зависание на неопределенное время .

Я читал, что решение этой проблемы с блокировкой буфера заключается в том, что я должен использовать буфер нулевого размера с нулевым указателем на сам буфер, чтобы событие чтения не блокировало его, иЯ должен использовать реальный буфер только тогда, когда я читаю реальные данные.

Я реализовал описанный выше обходной путь, и он работает, за исключением исходной проблемы, после отключения многих тысяч клиентов.В то же время, несколько тысяч застряли.

Конечно, я продолжаю понимать, что мой код неверен, поэтому я создал базовый сервер со встроенным dotnet классом SocketAsyncEventArgs (как официальный пример описывает), , который в основном делает то же самое, используя IOCP, и результаты такие же .

Все работает отличнокроме нескольких тысяч клиентов, отключающихся в одно и то же время, несколько тысяч событий отключения (чтение при отключении) не распознаются.

Я знаю, что должен выполнить операцию ввода-вывода и проверить возвращаемое значение, если сокетеще может выполнить IO, а если нет, то отключите его.Проблема в том, что в некоторых случаях мне нечего сказать сокету, я просто получаю данные, или если я делаю это периодически, это будет почти то же самое, что и опрос, и приведет к высокой нагрузке с тысячами соединений, что приведет к потере работы ЦП.

(я использую закрытие клиентов многочисленными методами закрытия, от gaceful разъединения до правильного закрытия TCP-сокета, как на Windows, так и на Linux-клиентах, результаты всегда одинаковы)

Мои вопросы:

    • Есть ли какое-либо известное решение этой проблемы?
    • Есть ли эффективный способ распознатьTCP (изящное) закрытие соединения удаленно?
    • Можно ли как-то установить тайм-аут чтения для чтения перекрывающихся сокетов?

Любая помощь будет признательна, спасибо!

...