解析后的byte数组解析成struct后变成垃圾

Parsed byte array turns into garbage after being parsed into a struct

我正在通过 UDP 接收数据包,我将其解析为结构,在特定情况下,我的数据全乱了,我无法弄清楚可能是什么问题。让我向您简要介绍一下我在做什么。

  1. UDP 接收器接收数据包并将其传递给回调 - 此阶段字节数组的大小为 1307 字节,这是数据包的预期大小
  2. 字节数组被编组(这是正确的术语吗?)到结构中 - 结构的大小现在是 1484 字节(不确定这是否相关)

在这个例子中,数据是从 Formula 1 2020 游戏发送的,奇怪的是 m_carTelemetryData 数组中的第一个条目(见下文)总是好的,数据是所有的声音。然而,第一个之后的 22 个条目中的每个条目都完全被 0 值、空值或结构中所有不同字段的完全古怪的值搞乱了。

我已经尝试了几种方法来查明问题所在,但我现在对我在这里处理的事情的了解已经到了尽头。我最好的猜测是在将数据转换为结构时出现问题,或者发生其他事情导致数据未对齐(?)。

到目前为止我尝试了什么

我的问题:

参考代码如下(如有遗漏,请告知):

包头

[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_tyresSurfaceTemperaturem_tyresInnerTemperature 应该是一个字节。根据协议规范,以下 returns 大小为 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;
}