主题
为支持 DataChannel,Flet 协议帧格式已升级
概述
Flet 0.86.0 引入了专用的数据通道(data channel),供需要在 Dart 和 Python 之间传输大量二进制数据(图像帧、音频缓冲、ML 张量)而无需经过 MsgPack 控制协议的控件使用。
启用这一点需要对 Flet 协议的线格式(wire format)做一次性的升级:
- 面向流的传输(基于 UDS / TCP 的
flet run开发模式)现在使用 4 字节小端长度前缀帧。以前的流式msgpack.Unpacker.feed解码方式已不复存在。 - 每种传输(socket、WebSocket、
dart_bridgeFFI、PyodidepostMessage)现在在每个数据包头部放一个 1 字节类型判别符:0x00—— MsgPack 编码的 Flet 控制帧(控件状态、事件)——内容与以前相同,只是前面多了一个类型字节。0x01—— 原始 DataChannel 帧([channel_id:u32 LE][payload])。
新格式不向后兼容:Flet 0.85 客户端无法与 Flet 0.86 服务器通信,反之亦然。本版本中 flet-cli 开发服务器与进程内 Python 运行时是一起升级的。
背景
Flet 以前在 UDS / TCP 上的线格式依赖 msgpack.Unpacker.feed 来从任意字节流分块重新组装消息。这对纯 MsgPack 流量有效,但无法与第二条原始字节逻辑流组合——如果没有带外标记,你无法区分一个不完整的 MsgPack 值和一个原始帧的开头。
加上 1 字节类型字节 + 4 字节长度前缀,以最小代价解决了这个问题:
- 接收方读取
[length][type][...],按类型字节分发,无需维护流式解码器状态。 - 面向消息的传输(WebSocket、
postMessage、dart_bridge)因为每条消息本身就是一个包,所以去掉长度前缀;它们保留类型字节。 - 每帧开销为 5 字节(面向消息)或 9 字节(面向流)——在任何会催生数据通道的负载大小下都不到 1%。
迁移指南
大多数用户——无需改动
如果你只使用 flet build 产物,或者运行与 flet 包版本匹配的 flet run(默认安装会一次性拉取两者),那就无事可做。CLI 与运行时是版本锁定的。
从不同安装运行 flet-cli 和 flet Python 包的用户
确保两者来自同一版本。常见的坑是全局 flet 安装加上 .venv 中版本不同的项目本地 flet——请同时升级或将两者都固定到 ≥ 0.86.0(或都 ≤ 0.85.x)。
版本不匹配会表现为 flet run 期间连接失败,并在开发服务器日志中显示解析错误。
拥有自定义后端或旁路、且使用 Flet 协议的用户
线格式变了。更新你的编码器/解码器:
- 在流传输上入站(UDS / TCP):读取 4 字节(长度,u32 LE),再读取那么多字节,首字节是类型判别符,其余是负载。
- 在消息传输上入站(WebSocket、
postMessage):每条消息的首字节是类型判别符,其余是负载。 - 出站:相同的形状,镜像对称。
如果你不使用数据通道,就把 0x01(原始 DataChannel)帧当作不透明数据处理——转发它们或丢弃它们,绝不要把它们喂给你的 MsgPack 解码器。
依赖 StreamingMsgpackDeserializer 的代码
Dart 端的类 package:flet/src/transport/streaming_msgpack_deserializer.dart 已被移除。没有公开的使用者——它是流传输帧格式的内部辅助类,既然每个包都是长度分隔的了,它就不再需要。如果你曾导入过它(你本不应该),请改用一次性的 msgpack.deserialize(bytes) 来解码每个入站缓冲区。
重写 MatplotlibChartCanvas 的自定义控件
MatplotlibChartCanvas 现在通过 [DataChannel] 而非 _invoke_method 参数来传输它的 apply_full / apply_diff / clear 帧。面向 Python 的方法签名未变(apply_full(image_bytes: bytes) 等),它们仍然是文档化的 API。但如果你子类化了该 canvas 并重写了 Dart 端的 _invokeMethod 处理器,那个重写不会再触发——Dart 端现在直接从通道消费 1 字节操作码 + PNG 负载。
时间线
- 变更于:
0.86.0
参考
- API:
flet.DataChannel(Python)和FletBackend.openDataChannel(Dart)——见flet/data_channel.py中的模块文档字符串;后续会补上专门的参考页。 - 发布说明:Flet 0.86.0