Рассмотрим метод 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()
из нескольких потоков, нет гарантии заказа, если вы не используете какой-либо другой механизм блокировки, чтобы заставить фактические вызовы произойти в определенном порядке. Каждый вызов, однако, правильно отправит свои данные в одном непрерывном потоке сетевых байтов.