将字节数组转换为结构时发生异常
本文关键字:异常 结构 字节 字节数 数组 转换 | 更新日期: 2023-09-27 18:21:47
我有一个用C编写的服务器应用程序,它必须通过套接字和C#gui客户端发送屏幕截图。问题是,由于异常,我无法将字节数组转换为结构。在C/C++中,将char数组强制转换为struct很简单,但在C#中就没那么简单了。这是测试代码:
public partial class Form1 : Form
{
const int magic = 101;
enum command {GET_SCREEN = 1, MOVE_MOUSE, CLICK_MOUSE };
public struct send_packet
{
public int magic;
public int cmd;
};
public struct recv_packet
{
public int magic;
public int code;
public int length;
public byte[] body;
};
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
int port = 4000;
TcpClient client = new TcpClient("127.0.0.1", 4000);
NetworkStream nws = client.GetStream();
BinaryWriter bw = new BinaryWriter(nws);
BinaryReader br = new BinaryReader(nws);
byte[] buff = new byte[512];
send_packet pkt = new send_packet();
pkt.magic = magic;
pkt.cmd = (int)command.GET_SCREEN;
while (true)
{
bw.Write(pkt.magic);
bw.Write(pkt.cmd);
br.Read(buff, 0, 512);
GCHandle pinnedPacket = GCHandle.Alloc(buff, GCHandleType.Pinned);
recv_packet rcv_pkt = (recv_packet)Marshal.PtrToStructure(pinnedPacket.AddrOfPinnedObject(), typeof(recv_packet));
//string str = System.Text.Encoding.Default.GetString(rcv_pkt.length);
string str = rcv_pkt.length.ToString();
MessageBox.Show(str);
}
}
}
可能是什么?异常的文本是俄语,但有最重要的信息:mscorlib.dll中的"System.AccessViolationException",尝试读取或写入受保护的内存。类似的东西。它发生在这个字符串recv_packet rcv_pkt = (recv_packet)Marshal.PtrToStructure(pinnedPacket.AddrOfPinnedObject(), typeof(recv_packet));
在这里,我得到了为什么这不起作用的解释和一种解决方案https://social.msdn.microsoft.com/Forums/vstudio/en-US/3c152957-91e7-43bf-91de-a047a3d124f5/exception-when-converting-byte-array-to-structure?forum=csharpgeneral
//Functions to turn byte arrays to structs.
public static byte[] RawSerialize<T>(T frqStruct)
where T : struct
{
int rawsize = Marshal.SizeOf<T>();
IntPtr i = IntPtr.Zero;
try
{
i = Marshal.AllocHGlobal(rawsize);
Marshal.StructureToPtr<T>(frqStruct, i, false);
byte[] rawdatas = new byte[rawsize];
Marshal.Copy(i, rawdatas, 0, rawsize);
return rawdatas;
}
finally
{
if (i != IntPtr.Zero)
{
Marshal.FreeHGlobal(i);
}
}
}
public static T RawDeserialize<T>(byte[] bytearray)
where T : struct
{
int len = Marshal.SizeOf<T>();
IntPtr i = IntPtr.Zero;
try
{
i = Marshal.AllocHGlobal(len);
Marshal.Copy(bytearray, 0, i, len);
return Marshal.PtrToStructure<T>(i);
}
finally
{
if (i != IntPtr.Zero)
{
Marshal.FreeHGlobal(i);
}
}
}
像这样使用
Struct struct1=new Struct();
byte[] outarr = RawSerialize(struct1);
struct1 = RawDeserialize<Struct>(outarr);
还要确保你的结构被正确地声明(包括大小等):
[StructLayout(LayoutKind.Sequential, Size = 24)]
public struct myStruct
{
public byte byte1;
public byte byte2;
public ushort reserved;
//Was char[16]
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
public string name; // null terminated
public uint version;
}