Асинхронная запись в поток сокетов безопасна?

Рассмотрим метод Socket.BeginSend(). Если два потока пула потоков должны были вызывать этот метод одновременно, будут ли их соответствующие сообщения в конечном итоге перемещаться друг с другом или класс сокета не позволяет это делать?

Ответ 1

Я нашел сообщение на форуме MSDN, который, кажется, отвечает на ваш вопрос.

  • Вы можете одновременно поставить несколько BeginSend. Вам не нужно блокировать

Edit:

Еще более интересная информация:

Если вы немного прокрутите фрагмент Замечание в документе MSDN BeginSend(), вы найдете интересное использование методов обратного вызова, которые могли бы быть релевантным для вас.

[...] Если вы хотите, чтобы исходный поток блокировался после вызова метода BeginSend, используйте метод WaitHandle.WaitOne. [...]

Ответ 2

Экземпляры .NET Socket не являются потокобезопасными, поскольку одновременные вызовы некоторых методов (одинаковые или разные) могут вызывать несогласованное состояние. Однако методы BeginSend() и BeginReceive() являются потокобезопасными по отношению к себе.

Безопасно иметь несколько невыполненных вызовов для каждого (или обоих).

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

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

Примечание: не предполагайте, что буфер 8k по умолчанию означает "Я могу быстро вызвать BeginSend() с точно 8k данных, а затем он будет блокироваться", как это верно:

  • 8K - это номер номинального размера, и буфер может уменьшаться и выражаться несколько.

  • По мере того, как вы оцениваете количество звонков на 8 тыс., в сеть будут отправляться данные, что уменьшит количество данных в очереди 8К.

В общем:

  • Если вы вызываете BeginSend() несколько раз в потоке, вы уверены, что отправители оставят машину в том порядке, в котором они были вызваны.

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