开发者

Mapping structs to memory in c#, is it worth it? Or is there a better way

开发者 https://www.devze.com 2023-03-10 15:25 出处:网络
I\'m sending some packets of data across the network and they arrive in byte[]s, lets say the structure is

I'm sending some packets of data across the network and they arrive in byte[]s, lets say the structure is

[int, int, byte, int]

If this was c++ I would declare a struct* and point to the byte[]. I'm doing this project in c# and I'm not sure whether it is worth it with marshalling overhead, or if there is a better way to handle it in c#, I'm all ears.

  • update, for clarity

Basically, what he is doing Marshaling a Byte array to a C# structure Except I开发者_如何学运维'm wondering if it is worth it.


I think marshaling is the best option. You could parse the byte array by yourself using BitConverter, but that would require more work on your part and is not as flexible.


The only real reason to do it that way would be to squeeze every last bit of performance out of the system. In my opinion, you're better off writing it using BitConverter to make sure it's working. Then, if getting the data is a performance bottleneck, consider doing the marshaling.

For example, given a struct:

struct MyStruct
{
    private int f1;
    private int f2;
    private byte f3;
    private int f4;
    public MyStruct(int i1, int i2, byte b1, int i4)
    {
        f1 = i1;
        f2 = i2;
        f3 = b1;
        f4 = i4;
    }
    // assume there are public get accessors
}

Then you can get create a new one from the buffer with:

var s = new MyStruct(BitConverter.ToInt32(buff, 0),
    BitConverter.ToInt32(buff, 4),
    BitConverter.ToUInt8(buff, 8),
    BitConverter.ToInt32(buff, 9));

That's a whole lot easier to write and verify than the marshaling, and probably will be fast enough for your needs.


Well, I guess everyone has their own 'favourite' way. When receiving protocol units over a byte stream in any OO language, I usually fire every received byte into a 'ProtocolUnit' class instance by calling its 'bool addByte() method. A state-machine in the class handles the bytes and error/sanity checks the assembled fields. If a ProtocolUnit has been received in its entirety, the addByte() method function returns true to indicate to the caller that a PDU has been correctly assembled. Usually, the instance is then queued off to whatever is going to handle it and a new ProtocolUnit created, (or depooled), so it can start to assemble the next PDU.

It's implicit that the start of a message can be identified so that, in case of an error, the state-machine can either reset itself, so dumping the erroneous data, or by returning 'true' to the addByte() call, setting a suitable errorMessage that the caller can check to decide what to do, (eg. if the errorMess property is "" then queue to handler else queue to error logger).

I'm sure that you consider this a massive overkill, but it works for me :)

Rgds, Martin

PS try to avoid protocols where the length is transmitted at the start and is the only way to identify message start/end. This is very fragile and prone to explosions, especially with non-secure transports like UDP. Even with TCP, I have known a x****x router that would occasionally add a null to packets...


As an alternative to BitConverter, wrap every byte[] in a MemoryStream, and extract the fields using a BinaryReader. Similar, but the stream maintains the offsets for you.

0

精彩评论

暂无评论...
验证码 换一张
取 消