Я работаю над библиотекой клиент / сервер для устаревшей реализации RPC и столкнулся с проблемами, когда клиент иногда зависал при ожидании получения ответного сообщения на сообщение запроса RPC. Оказывается, настоящая проблема была в моем коде создания сообщений (я не правильно обрабатывал границы сообщений при чтении данных из базового NetworkStream
), но это также вызывало у меня подозрения в отношении кода, который я использовал для отправки данных по сети в частности, в случае, когда сервер RPC отправляет большой объем данных клиенту в результате запроса клиента RPC.
Мой код отправки использует BinaryWriter
для записи полного «сообщения» в базовый NetworkStream
. Протокол RPC также реализует алгоритм пульса, при котором сервер RPC отправляет сообщения PING каждые 15 секунд. Пинги отправляются отдельным потоком, поэтому, по крайней мере, теоретически, пинг может быть отправлен, пока сервер находится в процессе потоковой передачи большого ответа клиенту.
Предположим, у меня есть метод Send
следующим образом, где stream
- это NetworkStream
:
public void Send(Message message)
{
//Write the message to a temporary stream so we can send it all-at-once
MemoryStream tempStream = new MemoryStream();
message.WriteToStream(tempStream);
//Write the serialized message to the stream.
//The BinaryWriter is a little redundant in this
//simplified example, but here because
//the production code uses it.
byte[] data = tempStream.ToArray();
BinaryWriter bw = new BinaryWriter(stream);
bw.Write(data, 0, data.Length);
bw.Flush();
}
Таким образом, у меня есть вопрос: является ли вызов bw.Write
(и, как следствие, вызов базового метода Stream
Write
) атомарным? То есть, если в потоке-отправителе все еще выполняется длительный Write
, и поток сердцебиения запускает и отправляет сообщение PING, будет ли этот поток блокироваться до завершения исходного вызова Write
или мне нужно добавить явное синхронизация с методом Send
, чтобы два Send
вызова не могли заглушить поток?