I'm working on a client/server library for a legacy RPC implementation and was running into issues where the client would sometimes hang when waiting to a receive a response message to an RPC request message. It turns out the real problem was in my message framing code (I wasn't handling message boundaries correctly when reading data off the underlying NetworkStream
), but it also made me suspicious of the code I was using to send data across the network, specifically in the case where the RPC server sends a large amount of data to a client as the result of a client RPC request.
My send code uses a BinaryWriter
to write a complete "message" to the underlying NetworkStream
. The RPC protocol also implements a heartbeat algorithm, where the RPC server sends out PING messages every 15 seconds. The pings are sent out by a separate thread, so, at least in theory, a ping can be sent while the server is in the middle of streaming a large response back to a client.
Suppose I have a Send
method as follows, where stream
is a 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();
}
So the question I have is, is the call to bw.Write
(and by implication the call to the underlying Stream
's Write
method) atomic? That is, if a lengthy Write
is still in progress on the sending thread, and the heartbeat thread kicks in and sends a PING message, will that thread block until the original Write
call finishes, or do I have to add explicit synchronization to the Send
method to prevent the two Send
calls from clobbering the stream?