c# - 解析的字节数组在解析成结构后变成垃圾
问题描述
我正在通过 UDP 接收数据包,我将这些数据包解析为结构,在特定情况下,我的数据变得一团糟,我无法弄清楚问题可能是什么。让我概述一下我在做什么。
- UDP Receiver 接收数据包并将其传递给回调 - 此阶段字节数组的大小为 1307 字节,这是数据包的预期大小
- 字节数组被编组(这是正确的术语吗?)成一个结构 - 结构的大小现在是 1484 字节(不确定这是否相关)
在这个例子中,数据是从Formula 1 2020比赛中发送的,奇怪的是m_carTelemetryData
数组中的第一个条目(见下文)总是好的,并且数据都是正确的。但是,第一个之后的 22 的每个条目都完全被结构中所有不同字段的 0 值、空值或完全古怪的值弄乱了。
我已经尝试了几件事来查明问题,但我现在已经对我在这里处理的事情的了解已经走到了尽头。我最好的猜测是,将数据转换为结构时出现了问题,或者发生了其他导致数据未对齐(?)的事情。
到目前为止我尝试了什么
- 将我的代码从“魔术编组”更改为使用手动读取数据逐字节
BinaryReader
- 不走运 - 使用手动检查数据
BitConverter.ToFoo(bytes, offset)
- 不走运 - Yolo 更改了
Pack
属性,假设那是我出错的地方 - 不走运 - 仔细检查文档以确保我得到了正确的数据类型 - 我相当有信心我正确地“翻译”了它们
- 把我的头撞在墙上 - 仍然没有运气
我的问题:
- 我的代码有什么明显的问题,我根本看不到吗?
- 附带问题:我假设结构的大小应该与创建它的字节数组的大小相匹配,我错了吗?
这是供参考的代码(如果缺少任何有用的信息,请告诉我):
包头
[StructLayout(LayoutKind.Sequential), Pack = 1]
struct PacketHeader2020 {
public ushort m_packetFormat;
public byte m_gameMajorVersion;
public byte m_gameMinorVersion;
public byte m_packetVersion;
public byte m_packetId;
public ulong m_sessionUUID;
public float m_sessionTime;
public uint m_frameIdentifier;
public byte m_playerCarIndex;
public byte m_secondaryPlayerCarIndex;
}
包
public struct CarTelemetryPacket2020
{
public PacketHeader2020 m_header;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 22)]
public CarTelemetryData2020[] m_carTelemetryData;
public ButtonFlag m_buttonStatus;
public byte m_mfdPanelIndex;
public byte m_mfdPanelIndexSecondaryPlayer;
public byte m_suggestedGear;
};
CarTelemetryData2020
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct CarTelemetryData2020
{
public ushort m_speed;
public float m_throttle;
public float m_steer;
public float m_brake;
public byte m_clutch;
public sbyte m_gear;
public ushort m_engineRPM;
public byte m_drs;
public byte m_revLightsPercent;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public ushort[] m_brakesTemperature;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public ushort[] m_tyresSurfaceTemperature;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public ushort[] m_tyresInnerTemperature;
public ushort m_engineTemperature;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public float[] m_tyresPressure;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public SurfaceType[] m_surfaceType;
}
字节[] -> 结构
public static T ByteArrayToStructure<T>(byte[] bytes) where T : struct
{
var handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
try
{
return (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T));
}
finally
{
handle.Free();
}
}
解决方案
我刚刚将您的代码粘贴到LINQPad中,发现了一些问题。该 CarTelemetryPacket2020
结构需要一个 pack 子句。也m_tyresSurfaceTemperature
应该m_tyresInnerTemperature
是一个字节。以下根据协议规范返回 1307 的大小。你是对的,尺寸应该匹配,我没有看到你的代码有任何其他明显的问题。
void Main()
{
System.Runtime.InteropServices.Marshal.SizeOf(typeof(CarTelemetryPacket2020)).Dump();
}
[StructLayout(LayoutKind.Sequential, Pack = 1) ]
public struct PacketHeader2020
{
public ushort m_packetFormat;
public byte m_gameMajorVersion;
public byte m_gameMinorVersion;
public byte m_packetVersion;
public byte m_packetId;
public ulong m_sessionUUID;
public float m_sessionTime;
public uint m_frameIdentifier;
public byte m_playerCarIndex;
public byte m_secondaryPlayerCarIndex;
}
// Added pack = 1
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct CarTelemetryPacket2020
{
public PacketHeader2020 m_header;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 22)]
public CarTelemetryData2020[] m_carTelemetryData;
public UInt32 m_buttonStatus;
public byte m_mfdPanelIndex;
public byte m_mfdPanelIndexSecondaryPlayer;
public byte m_suggestedGear;
};
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct CarTelemetryData2020
{
public ushort m_speed;
public float m_throttle;
public float m_steer;
public float m_brake;
public byte m_clutch;
public sbyte m_gear;
public ushort m_engineRPM;
public byte m_drs;
public byte m_revLightsPercent;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public ushort[] m_brakesTemperature;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
// Changed following to byte
public byte[] m_tyresSurfaceTemperature;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
// Changed following to byte
public byte[] m_tyresInnerTemperature;
public ushort m_engineTemperature;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public float[] m_tyresPressure;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public byte[] m_surfaceType;
}
推荐阅读
- javascript - 使用 chart.js 设置不均匀的刻度步长间距
- java - Java / OS如何检测视口上的点击坐标?
- google-app-engine - DataFlow 作业完成时如何通知
- jakarta-ee - 在 JAX-RS 请求过滤器之间共享数据的最佳方式
- angularjs - 在加载构造函数之前注入一个常量
- c# - 使用 LINQ 从对象列表中选择所有不同的对
- windows - 您可以使用 Powershell 打开/关闭键盘背光吗?
- eclipse - 无法解析 eclipse photon 中的“org.eclipse.swt”
- python - 我应该从类内部创建一个类实例吗?
- python-3.x - networkx.read_edgelist 使用的内存比它加载的文件多得多