MrDysprosium
MrDysprosium

Reputation: 499

Trying to convert a byte[] array that was received over a socket into a struct

Using TcpListener, I receive a byte array from a client and immediate try to create a stuct out of it (via Marshal.PtrToStructure)

This is what I have so far:

public static void ClientListener(object obj)                       
{

    TcpClient client = (TcpClient)obj;                              
    NetworkStream netStream = client.GetStream();      
    MemoryStream memStream = new MemoryStream();

    byte[] bytes = new byte[client.ReceiveBufferSize];              
    int bytesRead;
    while((bytesRead = netStream.Read(bytes, 0, bytes.Length)) > 0)    
    {
        memStream.Write(bytes, 0, bytesRead);
    }
    byte[] result = memStream.ToArray();                             

    Record test = new Record();
    test = ByteToStruct<Record>(result);
    Console.WriteLine(test.Station);            
    netStream.Close();                                                 
    memStream.Close();
    client.Close();
    Console.WriteLine("Closed");
    //Record test1 = new Record("a", "b", 1, 200, "e", "f", "g", 2, 3, "j", "k");
}

public static Record ByteToStruct<Record>(byte[] data)
{
    GCHandle gch = GCHandle.Alloc(data, GCHandleType.Pinned);

    try
    {
        return (Record)Marshal.PtrToStructure(gch.AddrOfPinnedObject(), typeof(Record));
    }
    finally
    {
        gch.Free();
    }
}           

Running this get me:

"An unhandled exception of type 'System.AccessViolationException' occurred in mscorlib.dll

Additional information: Attempted to read or write protected memory. This is often an indication that other memory is corrupt."

Any advice is wildly appreciated, I'm new to C#.

EDIT: I forgot to include the Record struct:

    public Record(string a, string b, int c, string d, string e, string f, string g, int h, int i, string j, string k)
    {
        Console.WriteLine("inside struct 0");
        Station = a;
        UserName = b;
        EvtActive = c;
        EvtTime = d;
        EvtTimeString = e;
        LocCode = f;
        LastLoop = g;
        CompLvl = h;
        RecordID = i;
        ConnectTime = j;
        Notes = k;

    }

Upvotes: 0

Views: 344

Answers (1)

pm100
pm100

Reputation: 50110

you are making a fundamental assumption here - that you can simply getsomething off the wire and do a byte blast into a struct (this may or may not be what your immediate problem is).

Much better is to read it off the wire field by field using BinaryReader (adn write it using BinaryWriter if you own the sender). BinaryReader can be instantiate directly on top of the network stream, it will do all the nice waiting for the correct number of bytes to be received etc.

ie.

var br = new BinaryReader(netStream);
var rec = new Record();
rec.Station = br.ReadString();
rec.EvtActive = br.ReadInt32();
.....

Upvotes: 1

Related Questions