在C#的UDP接收嵌入式设备端发送的结构体数据时,经过
//声明一个SDK_MSG_DEVICEINFO的结构体
[Serializable] // 指示可序列化
[StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
//[StructLayout(LayoutKind.Sequential, Pack = 1)] // 按1字节对齐
public struct SDK_MSG_DEVICEINFO
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)] // 声明一个字符数组,大小为64
public string hardware_ver; //硬件版本
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)] // 声明一个字符数组,大小为20
public string szMacAddr; //MAC STRING
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] // 声明一个字符数组,大小为32
public string szUID;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] // 声明一个字符数组,大小为32
public string szPwd;
};
///发送的时候先要把结构转换成字节数组
/// 将结构转换为字节数组
/// 结构对象
/// 字节数组
public byte[] StructToBytes(object obj)
{
//得到结构体的大小
int size = Marshal.SizeOf(obj);
//创建byte数组
byte[] bytes = new byte[size];
//分配结构体大小的内存空间
IntPtr structPtr = Marshal.AllocHGlobal(size);
//将结构体拷到分配好的内存空间
Marshal.StructureToPtr(obj, structPtr, false);
//从内存空间拷到byte数组
Marshal.Copy(structPtr, bytes, 0, size);
//释放内存空间
Marshal.FreeHGlobal(structPtr);
//返回byte数组
return bytes;
}
//接收的时候需要把字节数组转换成结构
/// byte数组转结构
///
/// byte数组
/// 结构类型
/// 转换后的结构
public object BytesToStruct(byte[] bytes, Type type)
{
//得到结构的大小
int size = Marshal.SizeOf(type);
//Log(size.ToString(), 1);
//byte数组长度小于结构的大小
if (size > bytes.Length)
{
//返回空
return null;
}
//分配结构大小的内存空间
IntPtr structPtr = Marshal.AllocHGlobal(size);
//将byte数组拷到分配好的内存空间
Marshal.Copy(bytes, 0, structPtr, size);
//将内存空间转换为目标结构
object obj = Marshal.PtrToStructure(structPtr, type);
//释放内存空间
Marshal.FreeHGlobal(structPtr);
//返回结构
return obj;
}
void RecvThread()
{
EndPoint ep = (EndPoint)endpoint;
while (true)
{
byte[] buf = new byte[1024];
SDK_MSG_DEVICEINFO deviceinfo = new SDK_MSG_DEVICEINFO();
int count = sock.ReceiveFrom(buf, ref ep);
Console.WriteLine(">>>>>ip>>" + (ep as IPEndPoint).Address.ToString() +">>>>>port>>>"+ (ep as IPEndPoint).Port.ToString()); // 发送方的IP地址
deviceinfo = (SDK_MSG_DEVICEINFO)this.BytesToStruct(buf, typeof(SDK_MSG_DEVICEINFO));
if (deviceinfo.szUID.Length > 0)
{
if (udpIPaddr.Count < UDP_MAX_VALUE)
{
String ipstr = (ep as IPEndPoint).Address.ToString();
//判断是否List中已经有搜索到的IP,如有跳过
if (udpIPaddr.Contains(ipstr) == false)
{
udpIPaddr.Add(ipstr);
Console.WriteLine("deviceinfo.szUID " + deviceinfo.szUID.ToString());
Console.WriteLine("deviceinfo.szPwd " + deviceinfo.szPwd.ToString());
Console.WriteLine("deviceinfo.szMacAddr " + deviceinfo.szMacAddr.ToString());
Console.WriteLine("deviceinfo.hardware_ver " + deviceinfo.hardware_ver.ToString());
sdkMsgDeviceInfo.Add(deviceinfo);
}
}
}
}
}
int count = sock.ReceiveFrom(buf, ref ep)接收到的数据长度是正确的,但是打印显示只能获取第一个字段deviceinfo.hardware_ver。
问题解决办法:
将结构体的按8的倍数对齐即可
//声明一个SDK_MSG_DEVICEINFO的结构体
[Serializable] // 指示可序列化
[StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct SDK_MSG_DEVICEINFO
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 24)] // 声明一个字符数组,大小为24
public string szMacAddr; //MAC STRING
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] // 声明一个字符数组,大小为32
public string szUID;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] // 声明一个字符数组,大小为32
public string szPwd;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)] // 声明一个字符数组,大小为64
public string hardware_ver; //硬件版本
};