You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Node.js中解包C#打包的结构体

解决Node.js中解包C++封送的C#结构体缓冲区问题

首先,你的C#结构体使用了LayoutKind.Sequential和Pack=1,这意味着结构体的字段是按定义顺序紧凑排列的,没有字节对齐填充,这给Node.js解析带来了便利——我们可以直接按字段顺序逐个读取对应的字节。

第一步:拆解结构体字段与对应Node.js读取方式

先把你的C#结构体字段(替换占位符后)和对应的Node.js Buffer读取方法、字节数整理出来:

C#类型字节数Node.js Buffer读取方法(小端,Windows默认)
byte1readUInt8(offset)
int4readInt32LE(offset)
ushort2readUInt16LE(offset)
fixed byte[N]Nbuffer.slice(offset, offset+N)转数组
short2readInt16LE(offset)

第二步:手动解析(原生Buffer API)

如果你不想依赖第三方库,可以直接用Node.js内置的Buffer API编写解析函数。先计算每个字段的偏移量(因为Pack=1,偏移量就是前面所有字段的字节总和):

function parseTheClass(rawBuffer) {
    // 先验证缓冲区大小:你的结构体总字节数是1+4+4+2+1*6+12+5+2 = 36
    if (rawBuffer.length !== 36) {
        throw new Error(`缓冲区大小错误:预期36字节,实际收到${rawBuffer.length}字节`);
    }

    let offset = 0;
    const parsed = {};

    // 读取单个byte字段
    parsed.Field1 = rawBuffer.readUInt8(offset);
    offset += 1;

    // 读取两个int字段
    parsed.Field2 = rawBuffer.readInt32LE(offset);
    offset += 4;
    parsed.Field3 = rawBuffer.readInt32LE(offset);
    offset += 4;

    // 读取ushort字段
    parsed.Field4 = rawBuffer.readUInt16LE(offset);
    offset += 2;

    // 读取6个byte字段
    parsed.Field5 = rawBuffer.readUInt8(offset++);
    parsed.Field6 = rawBuffer.readUInt8(offset++);
    parsed.Field7 = rawBuffer.readUInt8(offset++);
    parsed.Field8 = rawBuffer.readUInt8(offset++);
    parsed.Field9 = rawBuffer.readUInt8(offset++);
    parsed.Field10 = rawBuffer.readUInt8(offset++);

    // 读取固定长度字节数组
    parsed.Field11 = Array.from(rawBuffer.slice(offset, offset + 12));
    offset += 12;
    parsed.Field12 = Array.from(rawBuffer.slice(offset, offset + 5));
    offset += 5;

    // 读取short字段
    parsed.Field13 = rawBuffer.readInt16LE(offset);

    return parsed;
}

// 使用示例
// const cMarshaledBuffer = ...; // 从C++获取的封送缓冲区
// const data = parseTheClass(cMarshaledBuffer);
// console.log(data);

第三步:用第三方库简化解析(推荐)

如果结构体字段较多,手动计算偏移量容易出错,可以用binary-parser这类库来简化代码:

  1. 先安装依赖:
npm install binary-parser
  1. 编写解析器:
const Parser = require('binary-parser').Parser;

// 定义结构体解析器,指定小端字节序(Windows默认)
const TheClassParser = new Parser()
    .endianess('little')
    .uint8('Field1')
    .int32('Field2')
    .int32('Field3')
    .uint16('Field4')
    .uint8('Field5')
    .uint8('Field6')
    .uint8('Field7')
    .uint8('Field8')
    .uint8('Field9')
    .uint8('Field10')
    .array('Field11', { type: 'uint8', length: 12 })
    .array('Field12', { type: 'uint8', length: 5 })
    .int16('Field13');

// 使用示例
// const parsedData = TheClassParser.parse(cMarshaledBuffer);
// console.log(parsedData);

关键注意事项

  • 字节序:如果你的C++库是在大端字节序的系统(如部分嵌入式设备)编译的,需要把读取方法改成大端版本(比如readInt32BE),或者在binary-parser中设置.endianess('big')。
  • 缓冲区完整性:确保你获取的Buffer是完整的结构体数据,没有截断或多余字节,否则会导致解析结果错误。
  • 类型匹配:严格对应C#和Node.js的类型(比如C#的int是32位有符号,不能用readUInt32LE读取)。

内容的提问来源于stack exchange,提问作者Nightwolf

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 06:15:43