I send the serialized data over LAN network but sometimes the information is lost! Process is the following:
Sender:
string mydata
is being serializedstring mydata
is converted to byte[] bytes_of_mydata
int size_of_mydata
is the length of byte[] bytes_of_mydata
int size_of_mydata
itself is turned into byte[] bytes_size_of_mydata
byte[] bytes_of_mydata
and byte[] bytes_size_of_mydata
are sentReceiver:
byte[] bytes_size_of_mydata
int size_of_mydata
of the second message from byte[] bytes_size_of_mydata
byte[] bytes_of_mydata
, knowing exact length!byte[] bytes_of_mydata
to string mydata
string mydata
This approach usually works in most situations, but sometimes my data is not transmitted fully, so the string can't be deserialized.
I've debugged the received byte[]
on the "receiver" and here is what happens:
I get the size of second message:
int size_of_second_message = BitConverter.ToInt32(dataByteSize, 0); // 55185
I start to receive the second message to byte array:
Byte[] dataByte = new Byte[55185];
But starting from position 5840 I start to receive 0 (nulls), so the part "5840 - 55185" are all "0":
byte[5836] = 53;
byte[5837] = 57;
byte[5838] = 54;
byte[5839] = 49;
byte[5840] = 0; // information ends to flow
byte[5841] = 0;
byte[5842] = 0;
byte[5843] = 0;
//....
byte[55185] = 0;
The example from the above is taken from an actual debugger!
So what's the problem? It's like the connection is being lost during transmission!! Why is it happening and how do I counter this problem? It doesn't happen on "every-time" basis.
And here comes the code
Send:
//text_message - my original message
//Nw - network stream
MemoryStream Fs = new MemoryStream(ASCIIEncoding.Default.GetBytes(text_message));
Byte[] buffer = Fs.ToArray(); // total 55185 bytes (as in example)
Byte[] bufferSize = BitConverter.GetBytes(Fs.Length); // 32 bytes represent size
bufferSize = GetNewByteSize(bufferSize);
Nw.Write(bufferSize, 0, bufferSize.Length); // send size
Nw.Flush();
Nw.Write(buffer, 0, buffer.Length); // send message
Nw.Flush();
Receive:
//get first(SIZE) bytes:
int ReadSize = 0; int maxSize = 32; // 32 - constant!
Byte[] dataByteSize = new Byte[maxSize];
int origsize;
using (var strm = new MemoryStream())
{
ReadSize = Nw.Read(dataByteSize, 0, maxSize);
strm.Write(dataByteSize, 0, ReadSize);
strm.Seek(0, SeekOrigin.Begin);
origsize = BitConverter.ToInt32(dataByteSize, 0); // origsize = 55185
}
Nw.Flush();
//get next(MESSAGE) bytes:
string message = ""; int thisRead = 0;
int max = Convert.ToInt32(origsize); // origsize = 55185
Byte[] dataByte = new Byte[max];
using (var strm = new MemoryStream())
{
thisRead = Nw.Read(dataByte, 0, max);
strm.Write(dataByte, 0, thisRead);
strm.Seek(0, SeekOrigin.Begin);
using (StreamReader reader = new StreamReader(strm))
{
message = reader.ReadToEnd();
}
}
Nw.Flush();
// message - the message that is being transmitted partly (sometimes)!
I didn't want to post the code but you guys usually ask "show us what you've done", so here it is!
Temporary fix is to switch to StreamWriter, reader.
Receive + send (server):
NetworkStream Nw = new NetworkStream(handlerSocket.Client);
string toreceive = "";
StreamReader reader = new StreamReader(Nw);
toreceive = reader.ReadLine();
string text_message = "to send back";
StreamWriter writer = new StreamWriter(Nw);
writer.WriteLine(text_message);
writer.Flush();
Nw.Close();
Send + receive (client):
NetworkStream Nw = new NetworkStream(handlerSocket.Client);
StreamWriter writer = new StreamWriter(Nw);
writer.WriteLine("to send");
writer.Flush();
string toreceive = new StreamReader(Nw).ReadLine();
writer.Close();
Nw.Close();
I'm looking for a solution regarding original problem, but so far everything is working due to temporary fix.
TCP is a stream based protocol which lets you read as much data has yet been received. Just because you send data in one step, there is no guarantee that the data will be received in the same block. You have to loop on the receiving side until you have received all the data you anticipate.
By the way I think that your protocol with an explicit length field at the start is really good, it makes up for simple client code (as simple as it gets at least).
Some time back I asked a question on built in functionality to wait until X bytes of data is available: .NET blocking socket read until X bytes are available?. The answer is unfortunately no.