Высокопроизводительный сокет-сервер - Детали реализации - PullRequest
3 голосов
/ 15 октября 2011

Я провел свое исследование и знаю, что наилучший способ реализации высокопроизводительного сервера сокетов, как правило, заключается в следующем: использовать асинхронные операции с сокетами (специализированные SocketAsyncEventArgs / Operations для лучшей производительности) и при асинхронном обратном вызове отправьте запрос на очередь обработки, которая обрабатывается пулом потоков.

Мои вопросы по этой модели обработки - для максимальной производительности:

1) когда должна вызываться операция «Конец» сокета (например, EndAccept или EndReceive)? это должно быть вызвано в потоке обратного вызова (IOCP) перед постановкой в ​​очередь запроса? или вызывается, когда запрос извлекается из очереди и обрабатывается (рабочий поток)?

2) этот вопрос зависит от ответа на # 1. когда должна быть вызвана следующая операция «Начало»? Должны ли мы вызывать его еще до того, как вызовем EndOperation, или же мы должны вызывать его сразу после EndOperation (до запроса очереди / обработки)?

3) может ли очередь обработки быть просто пулом потоков .NET? Какие преимущества / недостатки было бы при использовании пула потоков .NET по сравнению с развертыванием собственной очереди синхронизированной обработки?

Любая помощь очень ценится.

1 Ответ

2 голосов
/ 15 октября 2011

1) EndReceive должно быть первым, что вы делаете в асинхронном обратном вызове. На самом деле, вы ничего не можете сделать в обратном вызове, пока не позвоните EndReceive, потому что именно это дает вам данные, которые были получены. См. Пример в Socket.EndReceive .

То же самое относится и к EndAccept , поскольку он дает вам сокет, с которым вы будете общаться.

2) Вам следует позвонить BeginAccept как можно скорее после EndAccept. В противном случае вы рискуете пропустить запросы соединения, если ваш ответный обратный вызов занимает слишком много времени для обработки. Конечно, если ваш обратный вызов подтверждения занимает много времени, вы делаете это неправильно. Опять же, то же самое относится и к BeginReceive: позвоните как можно скорее после EndRead, чтобы избежать потери данных. Или, если ваш коммуникационный протокол представляет собой модель запроса / ответа, где клиент ожидает ответа перед отправкой дополнительных данных, вы можете подождать, чтобы позвонить на номер BeginRead, пока вы не отправите ответ.

3) Обработка может быть пулом потоков .NET, хотя, если вы собираетесь использовать это, вы должны изучить использование параллельной библиотеки задач. Преимущество использования TPL состоит в том, что он очень сильно «стреляет и забывает» или, возможно, «стреляет, и он перезвонит, когда будет сделано». Недостатком использования TPL является то, что вашему приложению сложнее узнать, какие задачи ожидают выполнения. Если вы создаете собственную очередь синхронизированной обработки, вы всегда знаете, какие задания ожидают выполнения, и у вас есть возможность изучить очередь, отменить задания и т. Д. Если вы захотите сделать это с TPL, вы в конечном итоге создадите набор задач, которые вам нужно управлять, поскольку нет способа получить список ожидающих задач .

Но если вам не нужно видеть отложенные задачи, то TPL должен работать хорошо.

Связанные вопросы содержат полезную информацию.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...