简体   繁体   中英

C# Networking - Send struct buffer with StructLayout pack 1

I have a server client program which is written by myself. I am using socket with TCP protocol. I am trying to send a buffer from the client to the server. That buffer is struct which I convert it to byte array send it and on the server I convert it back to struct from byte array:

    public static byte[] StructToByteArray(loginStruct obj)
    {
        int len = Marshal.SizeOf(typeof(loginStruct));
        byte[] arr = new byte[len];

        IntPtr ptr = Marshal.AllocHGlobal(len);
        Marshal.StructureToPtr(obj, ptr, true);
        Marshal.Copy(ptr, arr, 0, len);

        Marshal.FreeHGlobal(ptr);
        return arr;

    }
    public static void ByteArrayToStruct(byte[] buffer, ref loginStruct obj)
    {
        int len = Marshal.SizeOf(typeof(loginStruct));

        IntPtr i = Marshal.AllocHGlobal(len);
        Marshal.Copy(buffer, 0, i, len);
        obj = (loginStruct)Marshal.PtrToStructure(i, obj.GetType());

        Marshal.FreeHGlobal(i);
    }

My struct:

[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct loginStruct
{
    public string userName;
    public string password;

    public loginStruct(string userName, string password)
    {
        this.userName = userName;
        this.password = password;
    }
}

I got a runtime error on the line:

obj = (loginStruct)Marshal.PtrToStructure(i, obj.GetType());

The error is:

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

On the server in the function ByteArrayToStruct len is equals to the buffer size which is 16.

If you are trying to send char * buffers of a fixed size, then the default marshaling for strings is probably not going to work for you. You should tag your strings with the MarshalAs attribute and specify the actual buffer size, so that .NET knows how much memory to allocate and copy in the unmanaged version of your structure. It would look something like this:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
struct loginStruct
{
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst=8)]
    public string userName;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst=8)]
    public string password;

    public loginStruct(string userName, string password)
    {
        this.userName = userName;
        this.password = password;
    }
}

For more information on how strings are marshaled across the managed/unmanaged boundary, see: Default Marshaling for Strings , especially the Strings Used In Structures section.

Incidentally, I don't think you need to specify Pack since your arrays are 8 bytes each, so there's no room for padding. You need to be very sure that you need to override the packing on a structure, especially if your code needs to work on both 32- and 64-bit systems. If the C definition doesn't include a #pragma pack or similar, you probably shouldn't either.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM