Как лучше всего обрабатывать приемы на многопротокольном сервере сокетов IOCP?

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

Однако после некоторых дальнейших исследований я нашел эту статью (пожалуйста, прочитайте: "Принятие Connections"), который рекомендует отделить операции принятия от процесса ввода-вывода, обрабатывая событие FD_ACCEPT в другом потоке, он также рекомендует это как средство предотвращения злонамеренных атак... Объяснение имеет смысл, но автор не принимать во внимание, что при таком подходе нет способа (по крайней мере, AFAIK) связать сокет с его данными контекста, поэтому применение этой рекомендации на сервере, который прослушивает несколько портов, привязанных к нескольким адресам, и каждый из которых обрабатывает другой протокол, включает обязательно операция поиска по каждому событию FD_ACCEPT, которая может (или не может) помешать первоначальному предложению развязать приемы ... и именно поэтому я в первую очередь перешел на порты завершения.

Итак.. Интересно, можно ли считать наличие 2 портов завершения, один для операций приема и один для процесса ввода-вывода, хорошей практикой в ​​общих термах, но особенно в отношении производительности... или лучше иметь только один?

Обновление:

После некоторых экспериментов я обнаружил, что отделить процесс принятия от процесса ввода-вывода с помощью двух IOCP (в отдельных потоках) просто нецелесообразно, и из-за этого нельзя добиться повышения эффективности. Таким образом, даже если он не упоминает об этом явно, автор прав, и единственный практический способ разделить эти два процесса — это обработать событие FD_ACCEPT со всеми вытекающими последствиями, но если он также прав в своих утверждениях, то единственный способ сделать его жизнеспособным в моем случае - найти эффективный способ связать каждый сокет с его контекстными данными или, другими словами; без поиска, поэтому исходный вопрос остается.


person george b    schedule 16.12.2013    source источник
comment
Если вы используете объектно-ориентированный язык, поддерживающий обратный вызов экземпляра, просто используйте его. Иначе почему проблема с поиском? При хорошей реализации хеш-таблицы у вас должно быть постоянное время поиска.   -  person Julien Lebosquain    schedule 16.12.2013


Ответы (1)


Если вы используете IOCP для потока данных, обычно лучше использовать IOCP для приема новых подключений, поэтому используйте AcceptEx() — хорошая идея. Не беспокойтесь о сложности работы с использованием его также для чтения первого фрагмента данных от однорангового узла, трудно избежать потенциальной атаки типа «отказ в обслуживании», которую это открывает, а прирост производительности для большинства конструкций серверов незначителен. Просто используйте его как перекрывающийся Accept, что избавляет вас от необходимости иметь отдельный поток принятия для каждого порта и поэтому очень хорошо масштабируется.

Лично я никогда не использовал идею FD_ACCEPT, которую предлагает статья, на которую вы ссылаетесь. Просто опубликуйте новый AcceptEx, когда он будет завершен, и опубликуйте настраиваемый номер в начале. Таким образом, у вас всегда будет «X» в ожидании принятия.

У меня есть несколько статей и примеров кода здесь, которые могут помочь.

person Len Holgate    schedule 16.12.2013
comment
Это интересный момент. Открывает ли использование AcceptEx() для чтения данных ворота для потенциальной атаки типа «отказ в обслуживании»? Как? Где-то есть статья с описанием этого? - person Marco Pagliaricci; 06.03.2014