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

Dart中如何将对象转换为字节数组?Flutter TCP自定义数据包序列化问题

Flutter 自定义TCP数据包序列化方案

以下是几种适配自定义格式的序列化方案,可直接将对象转成TCP传输用的字节数组:


1. 手动序列化(最灵活,适配自定义格式)

适合需要精确控制字节布局(比如字段顺序、大小端、字节长度)的场景,无额外依赖,性能最优。

示例代码:

import 'dart:typed_data';
import 'dart:convert';

class CustomPacket {
  final int id; // 4字节整数
  final String content; // 先存2字节长度,再存UTF-8内容
  final bool isSuccess; // 1字节布尔值(1为true,0为false)

  CustomPacket({required this.id, required this.content, required this.isSuccess});

  // 转成字节数组
  Uint8List toBytes() {
    final contentBytes = utf8.encode(content);
    final totalBytes = 4 + 2 + contentBytes.length + 1;
    final byteData = ByteData(totalBytes);

    // 写入ID(大端模式,可根据协议调整为Endian.little)
    byteData.setUint32(0, id, Endian.big);
    // 写入内容长度
    byteData.setUint16(4, contentBytes.length, Endian.big);
    // 写入内容字节
    for (int i = 0; i < contentBytes.length; i++) {
      byteData.setUint8(6 + i, contentBytes[i]);
    }
    // 写入布尔值
    byteData.setUint8(6 + contentBytes.length, isSuccess ? 1 : 0);

    return byteData.buffer.asUint8List();
  }

  // 可选:从字节数组解析回对象(接收端用)
  static CustomPacket fromBytes(Uint8List bytes) {
    final byteData = ByteData.view(bytes.buffer);
    final id = byteData.getUint32(0, Endian.big);
    final contentLength = byteData.getUint16(4, Endian.big);
    final contentBytes = bytes.sublist(6, 6 + contentLength);
    final content = utf8.decode(contentBytes);
    final isSuccess = byteData.getUint8(6 + contentLength) == 1;

    return CustomPacket(id: id, content: content, isSuccess: isSuccess);
  }
}

2. JSON转字节(开发高效,适合简单格式)

如果自定义格式允许JSON作为数据载体,可快速实现序列化,缺点是有额外字节开销。

示例代码:

import 'dart:typed_data';
import 'dart:convert';

class CustomPacket {
  final int id;
  final String content;
  final bool isSuccess;

  CustomPacket({required this.id, required this.content, required this.isSuccess});

  Uint8List toBytes() {
    // 转JSON字符串
    final jsonStr = jsonEncode({
      'id': id,
      'content': content,
      'isSuccess': isSuccess,
    });
    final jsonBytes = utf8.encode(jsonStr);

    // 先写入4字节的JSON长度(方便接收端判断数据包边界)
    final byteData = ByteData(4 + jsonBytes.length);
    byteData.setUint32(0, jsonBytes.length, Endian.big);
    for (int i = 0; i < jsonBytes.length; i++) {
      byteData.setUint8(4 + i, jsonBytes[i]);
    }

    return byteData.buffer.asUint8List();
  }

  static CustomPacket fromBytes(Uint8List bytes) {
    final byteData = ByteData.view(bytes.buffer);
    final length = byteData.getUint32(0, Endian.big);
    final jsonBytes = bytes.sublist(4, 4 + length);
    final jsonMap = jsonDecode(utf8.decode(jsonBytes)) as Map<String, dynamic>;

    return CustomPacket(
      id: jsonMap['id'] as int,
      content: jsonMap['content'] as String,
      isSuccess: jsonMap['isSuccess'] as bool,
    );
  }
}

3. Protobuf序列化(跨平台友好,适合复杂协议)

如果需要和其他平台(如Java、C++)交互,Protobuf是成熟方案,自动生成的代码能保证字节格式一致。

步骤:

  1. 定义.proto文件(比如custom_packet.proto):
syntax = "proto3";

message CustomPacket {
  int32 id = 1;
  string content = 2;
  bool is_success = 3;
}
  1. 安装protobuf工具链,生成Dart代码:
protoc --dart_out=. custom_packet.proto
  1. 在Flutter中使用生成的代码:
// 序列化
final packet = CustomPacket()
  ..id = 123
  ..content = "Hello TCP"
  ..isSuccess = true;
final bytes = packet.writeToBuffer();

// 反序列化
final receivedPacket = CustomPacket.fromBuffer(bytes);

方案选择建议:

  • 私有自定义协议优先选手动序列化,完全可控;
  • 快速开发选JSON转字节;
  • 跨平台交互选Protobuf。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 03:52:26