Я программирую библиотеку 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 (изящное) закрытие соединения удаленно?
- Можно ли как-то установить тайм-аут чтения для чтения перекрывающихся сокетов?
Любая помощь будет признательна, спасибо!