Reputation: 5931
Consider the following two methods for sending data and the one method for reading data:
public static void SendConsecutively(this NetworkStream stream)
{
byte[] header = {1, 2, 3, 4};
byte[] message = {5, 6, 7, 8, 9, 10};
stream.Write(header, 0, header.Length);
stream.Write(message, 0, message.Length);
}
public static void SendAllInOne(this NetworkStream stream)
{
byte[] headerAndMessage = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
stream.Write(headerAndMessage, 0, headerAndMessage.Length);
}
public static byte[] ReadMessage(this NetworkStream stream)
{
byte[] data = new byte[10];
int bytesRead = stream.Read(data, 0, 10);
return data;
}
Does it make a difference whether or not to split the data into two chunks (like in SendConsecutively
) compared to not splitting the data (like in SendAllInOne
)?
The thing is, in my tests, ReadMessage
always reads 10 bytes. And the 3rd-party-server, which I am sending header and message to (but do not know how it is implemented), usually also receives 10 bytes. But sometimes - in rare cases - they tell me that the 3rd-party-server receives only 4 bytes. I have to deal with the problem, that that server only received 4 bytes, despite I am sure that I have sent 10 byte using SendConsecutively
. (Because there was no Exception in my logs, which means that both stream.Write
call have been issued, for sure.)
So, one question is: What happens between two consecutive stream.Write
calls? I thought: nothing, because the documentation to NetworkStream.Flush
says: "The Flush method implements the Stream.Flush method; however, because NetworkStream is not buffered, it has no affect on network streams." [1]
I am provided with Wireshark logs where a TCP packet can be seen that only consists of the four header bytes. Does each stream.Write
call produce one TCP packet? But then again, do I even have to care about how my data is split into TCP packets? Because large messages will be segmented into multiple TCP packets anyways, won't they? (Yes, there are also large messages sent which are way larger than the 6 bytes I have used for the example above - e.g.: 4 bytes header + 3000 bytes message)
Is my SendConsecutively
method flawed in any way which could cause such problems on the receiver-side (Also considering that message
could be 3000 bytes, not just 6 like in the example code)?
Could it be, that it is rather a problem of the 3rd-party-server? If that server would be implemented just like the ReadMessage
method above, it could be a problem. Because sometimes (I think this must happen, when messages get segmented over TCP), ReadMessage
would read fewer bytes than have been sent and return a smaller number in bytesRead
than the actual message's length. The rest of the message is available on the stream (a few milliseconds?) later. Any thoughts on this?
[1] MSDN, NetworkStream.Flush, https://msdn.microsoft.com/en-us/library/system.net.sockets.networkstream.write(v=vs.110).aspx
Upvotes: 1
Views: 1371
Reputation: 13522
The network stream is an abstraction - it hides the implementation details. Normally the developer can ignore how exactly the sent data is transferred - in multiple packets or as single one, which protocol is used, etc. However, it is important (at least for me, and probably for everyone working with the network streams) to remember a few facts about the I/O:
Most of these facts do not depend on the technology used on both ends of the wire. It can be Java on one side and .NET on another - normally it does not matter as long as the channel is just a byte stream.
With this in mind, the answer to your questions:
Does it make a difference whether or not to split the data into two chunks (like in SendConsecutively) compared to not splitting the data (like in SendAllInOne)? ... What happens between two consecutive stream.Write calls? ... Is my SendConsecutively method flawed in any way which could cause such problems on the receiver-side (Also considering that message could be 3000 bytes, not just 6 like in the example code)?
There can be difference depending on the internal implementation of the socket. At may result in two sequential sends or be merged into one send. NetworkStream sends calls Send of the underlying socket. This call is converted to the socket's Send() and then it really depends on the implementation of WinSock's send.
For the receiver it does not matter how exactly the data was sent. Network layer can split data in different chunks without any correlation to the size of sent chunks.
Upvotes: 1