сколько асинхронных запросов сокетов может происходить на одном сокете? - PullRequest
9 голосов
/ 18 февраля 2010

Когда я вызываю BeginSend для сокета, я передаю делегат, который будет вызван (другим потоком) при отправке данных.

Что произойдет, если я вызову BeginSend в другой раз, пока первыйеще не был выполнен обратный вызов?

Как правильно отправлять данные?сделать BeginSend, а при обратном вызове сделать EndSend и начать другую отправку?Или на самом деле целесообразно, чтобы несколько BeginSend работали одновременно?

это страница BeginSend в MSDN, которая не дает ответа на этот вопрос: BeginSend msdn

Ответы [ 2 ]

17 голосов
/ 18 февраля 2010

Как О.К.В. говорит, что несколько ожидающих BeginSend вызовов будут работать нормально. Вы, вероятно, должны иметь в виду некоторые вещи, хотя.

Во-первых, если это сокет TCP, то это все еще один поток данных от однорангового узла.

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

В-третьих, если вы используете TCP и отправляете быстрее, чем может получить код на другом конце сокета, вы можете заполнить окно TCP, и стеки TCP начнут выполнять управление потоком в вашем потоке данных. Если вы продолжаете совершать вызовы BeginSend, то вы МОЖЕТЕ оказаться в ситуации, когда ваши обратные вызовы будут дольше и дольше вызываться, так как стек TCP на сервере ставит в очередь данные для отправки (обратный вызов вы получаете только после отправки данных и управление потоком на основе окна TCP будет предотвращать отправку новых данных до тех пор, пока окно TCP не перестанет быть «полным», т. е. узел отправил ACK для некоторых данных, которые in flight).

Затем вы можете попасть в ситуацию, когда вы используете ресурсы на отправляющем компьютере неконтролируемым образом (вы запускаете BeginSend и не знаете, когда он завершится, и каждая отправка использует память для отправляемого буфера и потенциально non-paged pool в коде Winsock ... Non-paged pool является общесистемным ресурсом и довольно редко встречается в операционных системах до Vista, и некоторые драйверы с плохим поведением могут отображать синий экран, если non-paged pool низкий или исчерпан. Вы также можете блокировать страницы памяти в памяти, и существует еще одно общесистемное ограничение на количество заблокированных страниц памяти.

Из-за этих проблем обычно лучше реализовать собственный контроль потока на уровне протокола, который ограничивает количество вызовов BeginSend, которые могут быть ожидающими в любой момент времени (возможно, с использованием ACK уровня протокола), или для работы с TCP Окно управления потоком и использовать завершение ожидающей отправки для отправки новой отправки, и вы можете поставить в очередь данные для отправки в вашу собственную память и иметь полный контроль над используемыми ресурсами и тем, что вы делаете, если ставите в очередь «слишком много» данных. Подробнее об этом см. В моем блоге: http://www.serverframework.com/asynchronousevents/2011/06/tcp-flow-control-and-asynchronous-writes.html

См. Этот ответ: что происходит, когда сервер tcp / udp публикует быстрее, чем потребляет клиент? для получения дополнительной информации об управлении потоком TCP Window и что происходит с перекрывающимся вводом-выводом (на земле C ++), когда Вы игнорируете это и посылаете слишком много дублированных сообщений ...

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

4 голосов
/ 18 февраля 2010

Исходя из того, что я прочитал здесь , кажется, что возможно одновременное выполнение нескольких BeginSend.

Выдержка:

  1. Вы можете поставить в очередь несколько BeginSends одновременно. Тебе не нужно блокировка
  2. Если вы не создаете метод обратного вызова, как вы узнаете, когда отправить успешно? Вы можете игнорировать успех - больше похоже на огонь и забудь - метод, но тогда ты хотя бы нужно знать, когда можно закончить ваша программа.
  3. Другая вещь, которую вы можете сделать, это использовать IAsyncResult, который вы получаете от BeginSend. Вы можете использовать WaitHandle ждать завершения операции. Но это побеждает всю цель во-первых, используя Async.
  4. Моя рекомендация - использовать обратный вызов и убедиться, что обратный вызов называется и номер отправленные байты фактически отправлены и Изящно завершите операцию отправки.

Обновление:
Пробовал одновременно BeginSend на основе кодов на MSDN и данные отправляются без исключения. Однако имейте в виду, что соединение для одного и того же сокета должно быть открыто заранее. Одновременное BeginConnect не будет работать.

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