0

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;

    }
2
  • Seems like your over complicating things there. I presume Record is your struct? Does it have a Byte array property? If not what your doing wont work. You'll need to give it a Property that is a byte[] to do that, you can't just magic a struct to have some other type in in it. In general structs in C# are misunderstood/used and your better off just using a class. Commented Aug 4, 2016 at 21:06
  • What would I do after giving it a byte[] property? Are you saying all of its variables in the constructor would be byte[]s? Commented Aug 4, 2016 at 21:14

1 Answer 1

1

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();
.....
Sign up to request clarification or add additional context in comments.

6 Comments

You say "field by field", but what does that mean? When I receive the data (I do not own the sender) it comes in a giant block of 1324 bytes.
Now that is interesting. So, if this client (that I do not own) is sending me a big ole dump of about 1324 bytes of data, but it's always in the order that I have setup in my Record struct, BinaryReader will take the "first" String and apply it to Station, then take the "second" String and apply it to Username, etc... or do I have to tell BinaryReader how my bytes are dedicated to each variable? Thank you for all your help btw, I REALLY appreciate it.
Alright, well I tried your example verbatim, here's what happened: rec.Station = br.ReadString(); returned ""An unhandled exception of type 'System.IO.EndOfStreamException' occurred in mscorlib.dll Additional information: Unable to read beyond the end of the stream.""
Well, it looks like BinaryReader can't really read anything that wasn't sent using BinaryWriter.... Am I wrong about that?
no - it has a specific format it expects, it doesnt mind who creates it. If you dont like that then you have to marshall each field of the wire yourself, you cannot bit blit
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.