TcpClient missing data

I am trying to write network part for my game in C# using System.Net.Sockets and TcpClient class.

What am I doing wrong, and how can I evade this wrong data streams?

Am I just sending too much data in 1 ms and it is needed to send it over time?

This is the sending information:

TcpClient client;

public void SendData(byte[] b)
    {
        //Try to send the data.  If an exception is thrown, disconnect the client
        try
        {
            lock (client.GetStream())
            {
                client.GetStream().BeginWrite(b, 0, b.Length, null, null);
            }
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);
        }
    }

This is the receiving information:

byte[] readBuffer;
int byfferSize = 2048;

private void StartListening()
    {
        client.GetStream().BeginRead(readBuffer, 0, bufferSize, StreamReceived, null);
    }

    private void StreamReceived(IAsyncResult ar)
    {
        int bytesRead = 0;
        try
        {
            lock (client.GetStream())
            {
                bytesRead = client.GetStream().EndRead(ar); // просмотр длины сообщения
            }
        }
        catch (Exception ex)
        { MessageBox.Show(ex.Message); }

        //An error happened that created bad data
        if (bytesRead == 0)
        {
            Disconnect();
            return;
        }

        //Create the byte array with the number of bytes read
        byte[] data = new byte[bytesRead];

        //Populate the array
        for (int i = 0; i < bytesRead; i++)
            data[i] = readBuffer[i];

        //Listen for new data
        StartListening();

        //Call all delegates
        if (DataReceived != null)
            DataReceived(this, data);
    }

It is main network code.

Upvotes: 0

Views: 2266

Answers (1)

Jim Mischel
Jim Mischel

Reputation: 134125

I don't know what you do with the data after you've received it, but it's quite possible that you're not reading all of the data from the connection. You have:

bytesRead = client.GetStream().EndRead(ar);

There's no guarantee that the number of bytes you've read are all of the bytes that the server sent. For example, the server could have sent 2,048 bytes, but when you called Read, there were only 1,024 bytes available. The rest of them are still "in transit." As the documentation for NetworkStream.Read says:

The Read operation reads as much data as is available, up to the number of bytes specified by the size parameter

You could be getting partial packets. If your DataReceived handlers assume that the data buffer contains a complete packet, then you're going to have problems.

To reliably read from a network stream, you need to know how much data you're supposed to read, or you need a record separator. Something has to make sure that if you're expecting a complete packet that you get a complete packet before you try to process it. Your code just checks to see if bytesRead is not 0. If it's anything else, you just pass it on. This is going to be a problem unless your DataReceived handlers know how to buffer partial packets.

On another note, you really don't need to lock the network stream. Unless you can have several threads reading from the same stream. And that would be disastrous. Ditch the lock. You don't need it.

Upvotes: 2

Related Questions