Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can one simplify network byte-order conversion from a BinaryReader?

System.IO.BinaryReader reads values in a little-endian format.

I have a C# application connecting to a proprietary networking library on the server side. The server-side sends everything down in network byte order, as one would expect, but I find that dealing with this on the client side is awkward, particularly for unsigned values.

UInt32 length = (UInt32)IPAddress.NetworkToHostOrder(reader.ReadInt32());

is the only way I've come up with to get a correct unsigned value out of the stream, but this seems both awkward and ugly, and I have yet to test if that's just going to clip off high-order values so that I have to do fun BitConverter stuff.

Is there some way I'm missing short of writing a wrapper around the whole thing to avoid these ugly conversions on every read? It seems like there should be an endian-ness option on the reader to make things like this simpler, but I haven't come across anything.

like image 218
Zach Lute Avatar asked Sep 23 '08 21:09

Zach Lute


People also ask

What is network byte order?

Network addresses in a given network must all follow a consistent addressing convention. This convention, known as network byte order, defines the bit-order of network addresses as they pass through the network. The TCP/IP standard network byte order is big-endian.

Do network communications always use big-endian byte order?

From this product guide, under the Big Endian link: Networks generally use big-endian order, and thus it is called network order when sending information over a network in a common format.

Why does networking use big-endian?

Big-endian CPUs order bytes within words so that the most significant byte is stored at the lowest byte address; little-endian CPUs, including IA-32 processors, use the opposite byte placement. When communicating across a network, it is possible that two machines may use different byte orderings.


1 Answers

There is no built-in converter. Here's my wrapper (as you can see, I only implemented the functionality I needed but the structure is pretty easy to change to your liking):

/// <summary>
/// Utilities for reading big-endian files
/// </summary>
public class BigEndianReader
{
    public BigEndianReader(BinaryReader baseReader)
    {
        mBaseReader = baseReader;
    }

    public short ReadInt16()
    {
        return BitConverter.ToInt16(ReadBigEndianBytes(2), 0);
    }

    public ushort ReadUInt16()
    {
        return BitConverter.ToUInt16(ReadBigEndianBytes(2), 0);
    }

    public uint ReadUInt32()
    {
        return BitConverter.ToUInt32(ReadBigEndianBytes(4), 0);
    }

    public byte[] ReadBigEndianBytes(int count)
    {
        byte[] bytes = new byte[count];
        for (int i = count - 1; i >= 0; i--)
            bytes[i] = mBaseReader.ReadByte();

        return bytes;
    }

    public byte[] ReadBytes(int count)
    {
        return mBaseReader.ReadBytes(count);
    }

    public void Close()
    {
        mBaseReader.Close();
    }

    public Stream BaseStream
    {
        get { return mBaseReader.BaseStream;  }
    }

    private BinaryReader mBaseReader;
}

Basically, ReadBigEndianBytes does the grunt work, and this is passed to a BitConverter. There will be a definite problem if you read a large number of bytes since this will cause a large memory allocation.

like image 146
Nick Avatar answered Nov 05 '22 03:11

Nick