Search code examples
c#socketsnetwork-programmingendianness

Socket.BeginReceive(): How handle big endian data on "ReceiveCallback"?


The following code (mirror in this sample) seems work fine to receive little endian data (tested), but i'm needing to receive big endian (from a Android phone) and any attempt to revert the bytes result in inverted bytes with a strange character on end of data (see image below). And yes, i'm sending UTF8 bytes from android code.

IMAGE

I'm working in a async version of this code (see client part) that works very fine to receive bin data and text since the you revert the bytes order after first while iteration.

Here is the problematic code:

`class Client
{
    public Socket socket;
    public Guid ID;
    public string RemoteAddress;
    public byte[] Buffer = new byte[1024];
    public int DataSize = 0;
    public int PrefixSize = 0;
    public uint tickCount = 0;
    public bool DataSizeReceived = false;
    public bool lengthRead = false;
    public MemoryStream Data = new MemoryStream();

    public Client(Socket socket)
    {
        this.socket = socket;
        ID = Guid.NewGuid();
        RemoteAddress = socket.RemoteEndPoint.ToString();
    }
}

private bool _IsConnected(Socket socket)
{
    try
    {
        return !(socket.Poll(1000, SelectMode.SelectRead) && socket.Available == 0);
    }
    catch (SocketException)
    {
        return false;
    }
}

private void ReceiveCallback(IAsyncResult ar)
{
    int dataOffset = 0;
    int restOfData = 0;
    int dataRead = 0;
    Boolean StreamClosed = false;
    long cDataLength = 0;
    long LastiDataLength = 0;

    SocketError socketError = SocketError.TypeNotFound;

    Client c = (Client)ar.AsyncState;

    if (!c.socket.Connected)
    {
        // Not Connected anymore ?
        return;
    }

    try
    {
        dataRead = c.socket.EndReceive(ar, out socketError);
    }
    catch (Exception)
    {
       // Your code goes here..
    }

    if (socketError != SocketError.Success)
    {
        // Has Connection been lost ?
        OnConnectionDropped(client);
        return;
    }

    if (dataRead <= 0)
    {
       // Has connection been lost ?
        OnConnectionDropped(client);
        return;
    }
    
    while (dataRead > 0)
    {
        if (!c.DataSizeReceived)
        {
            if (!c.lengthRead)
            {
                c.PrefixSize = dataRead;
                Array.Resize(ref c.Buffer, c.PrefixSize);
                Array.Reverse(c.Buffer);
                c.lengthRead = true;
            }

            if (c.Data.Length > 0)
            {
                restOfData = c.PrefixSize - (int)c.Data.Length;
                c.Data.Write(c.Buffer, dataOffset, restOfData);
                dataRead -= restOfData;
                dataOffset += restOfData;
            }
            else if (dataRead >= c.PrefixSize)
            {
                c.Data.Write(c.Buffer, dataOffset, c.PrefixSize);
                dataRead -= c.PrefixSize;
                dataOffset += c.PrefixSize;
                c.lengthRead = false;

                // Handle the received messsage

               string text = Encoding.UTF8.GetString(c.Data.GetBuffer(), 0, (int)c.Data.Length);
               MessageBox.Show(text);
                
               // ============================
            }
            else
            {
                c.Data.Write(c.Buffer, dataOffset, dataRead);
                dataOffset += dataRead;
                dataRead = 0;
            }

            if (c.Data.Length == c.PrefixSize)
            {
                c.DataSize = BitConverter.ToInt32(c.Data.GetBuffer(), 0);
                c.DataSizeReceived = true;
                c.Data.Position = 0;
                c.Data.SetLength(0);
                c.lengthRead = false;
            }
            else
            {
                c.socket.BeginReceive(c.Buffer, 0, c.Buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), c);
                return;
            }
        }

        try
        {
            cDataLength = c.Data.Length;
            LastiDataLength = cDataLength;
        }
        catch (ObjectDisposedException)
        {
            StreamClosed = true;
        }
        if (!StreamClosed)
        {
            if ((cDataLength + dataRead) >= c.DataSize)
            {
                restOfData = c.DataSize - (int)c.Data.Length;

                c.Data.Write(c.Buffer, dataOffset, restOfData);

                // Handle the received messsage

               string text = Encoding.UTF8.GetString(c.Data.GetBuffer(), 0, (int)c.Data.Length);
               MessageBox.Show(text);
                
               // ============================

                dataOffset += restOfData;
                dataRead -= restOfData;

                c.Data = new MemoryStream();
                c.Data.Position = 0;
                c.DataSizeReceived = false;
                c.DataSize = 0;

                if (dataRead == 0)
                {
                    if (_IsConnected(c.socket))
                    {
                        c.socket.BeginReceive(c.Buffer, 0, c.Buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), c);
                        return;
                    }
                }
                else
                    continue;
            }
            else
            {
                if (_IsConnected(c.socket))
                {
                    c.Data.Write(c.Buffer, dataOffset, dataRead);

                    c.socket.BeginReceive(c.Buffer, 0, c.Buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), c);

                    dataRead = 0;
                }
            }
        }
        else
        {
            if (LastiDataLength + dataRead == c.DataSize)
            {
                if (_IsConnected(c.socket))
                {
                    c.socket.BeginReceive(c.Buffer, 0, c.Buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), c);
                }
                return;
            }
            else
            {

            }
        }

        if (!_IsConnected(c.socket))
            dataRead = -1;
    }
}`

Solution

  • OK, i not had get size of message correctly. Below is the solution:

    if (!c.lengthRead)
    {
        byte[] BodyLengthR = new byte[4];
        Array.Copy(c.Buffer, BodyLengthR, 4);
        Int32 Endian = BitConverter.ToInt32(BodyLengthR, 0);
        Int32 BodySize = IPAddress.NetworkToHostOrder(Endian);
    
        c.PrefixSize = BodySize + 4;
        Array.Resize(ref c.Buffer, c.PrefixSize);
        c.lengthRead = true;
    }
    
    //...
    
    string text = Encoding.UTF8.GetString(c.Data.GetBuffer(), 4, (int)c.Data.Length); // 4 = ignore header
    MessageBox.Show(text);