views:

415

answers:

3

When i write to a network stream two seperate byte array, i sometimes dont get the first byte array. Why is that?

For eg This fails, the header is not received, sometimes by Read() on other side

            byte[] header = msg.getByteHeader();
            byte[] data = msg.getByteData();
            clientStream.Write(header, 0, header.Length);
            clientStream.Write(data, 0, data.Length);
            clientStream.Flush();

however this succeeds

                NetworkStream clientStream = tcpClient.GetStream();
                byte[] header = msg.getByteHeader();
                byte[] data = msg.getByteData();
                int pos = 0;
                Array.Copy(header, 0, message, pos, header.Length);
                pos += header.Length;
                Array.Copy(data, 0, message, pos, data.Length);
                clientStream.Write(message, 0, message.Length);

This is how my Read() looks

           try
            {
                //blocks until a client sends a message
                bytesRead = clientStream.Read(message, 0, 4);
                //string stringData = Encoding.ASCII.GetString(message, 0, bytesRead);
                len = BitConverter.ToInt32(message, 0);
                //MessageBox.Show(len.ToString());
                bytesRead = clientStream.Read(message, 0, 5 + len);

            }
A: 

Aren't you overwritting what you read in the first call to read with the second call? The second argument to Read is the offset at which to start storing the data read, both calls use 0 so the second overwrites the first...

Simon Fox
no, what i read in the first call i store it in the len by converting it to integer, then i read on the same position, but my very first call to read does not read the first set of bytes i sent
Kazoom
so **message** buffer is empty after the first call to read?
Simon Fox
A: 

i believe this is a timing issue. There's a lag between when you first open socket communication and when you can read the first data from the buffer. It's not instantaneous. You can query the DataAvailable boolean status of network stream before attempting to read. If there's no DataAvailable, Sleep the thread for say 100 ms and then try reading again.

Paul Sasik
but isn't that against the tcp ip protocol, there should be no data loss, its a reliable connection oriented protocol
Kazoom
i don't know what to tell you. i just had to deal with this the day before yesterday. And... this wouldn't be the first time that an API isn't up to a particular spec.
Paul Sasik
And... it's always possible to have an empty buffer. No matter how mch data you're expecting, you always need to account for an empty buffer. That's why there's a DataAvailable property for you to query before you attempt a read.
Paul Sasik
A: 

You could troubleshoot it by commenting out the second Write and see if your server is sent any data.

Your reading mechanism does look very very fragile and I'd agree with Simon Fox that it does not look like it's correct. Why is the second read asking for len + 5 bytes? I would have thought it would only be len bytes since the first read was for the 4 header bytes.

If I was you I'd add a delimiter to the start of your header transmission. That will allow your receivers to scan for that to determine the start of a packet. With TCP you will often get fragemented transmissions or multiple transmissions bundled into the same packet. Things will go wrong once you deploy to real networks such as the internet if you are always relying on getting exactly the number of bytes you request.

Either that or switch to UDP where you can rely on having one transmission per packet.

sipwiz