- Protocol inspiration: ypo/flute - FLUTE implementation in Rust
This library implements the following RFCs
| RFC | Title | Link |
|---|---|---|
| RFC 6726 | FLUTE - File Delivery over Unidirectional Transport | https://www.rfc-editor.org/rfc/rfc6726.html |
| RFC 5052 | Forward Error Correction (FEC) Building Block | https://www.rfc-editor.org/rfc/rfc5052 |
| RFC 5510 | Reed-Solomon Forward Error Correction (FEC) Schemes | https://www.rfc-editor.org/rfc/rfc5510.html |
sequenceDiagram
participant MS as Meta Sender
participant MR as Meta Receiver
participant FS as File Sender
participant FR as File Receiver
Note over MS,MR: Step 1: FDT Metadata Transfer
MS->>MR: Send FDT XML<br/>(File Description Table: OTI, File Size, File Name, FEC Type)
Note right of MS: FDT 重发 3 次<br/>确保跨设备接收
Note over MR,FR: Step 2: Receiver Preparation
MR->>FR: Parse FDT & Start File Receiver<br/>Register Receiver for fdtID
Note over MS,FS: Step 3: Data Transmission
MS->>FS: Start File Sender
FS->>FR: Send File Data Packets<br/>(LCT Header + Symbol)
Note right of FS: 支持 NoCode/RaptorQ/ReedSolomon<br/>速率限制 + 百分比控制
Note over FR: Step 4: Data Processing
FR->>FR: Decode Symbols & Write Chunks<br/>Async Queue (4096 buffer)
Note over FR: Step 5: File Assembly & Cleanup
FR->>FR: Reassemble File & Verify MD5<br/>Close Port
- 发送端指定接收端 IP 地址,通过 UDP 单播传输文件
- 适用于点对点传输,支持跨网段(需路由可达)
- 配置简单,无需特殊网络设置
- 使用多播地址(如
239.1.1.1)进行一对多传输 - 支持同一子网内多个接收端同时接收
- 发送端自动查路由表选择出口网卡,无需手动指定
- 发送端设置
IP_MULTICAST_TTL=2,支持跨 1 个路由器 - 接收端自动在所有可用接口上加入多播组(
INADDR_ANY)
多播配置示例:
# 发送端(自动选择网卡)
go run ./cmd/flute_sender/main.go --cli --file test.pdf --dest-ip 239.1.1.1
# 接收端
go run ./cmd/flute_receiver/main.go --cli --dest-ip 239.1.1.1手动指定网卡(多网卡环境需要显式控制时):
# 发送端(指定以太网接口 192.168.0.12)
go run ./cmd/flute_sender/main.go --cli --file test.pdf --dest-ip 239.1.1.1 --mcast-iface 192.168.0.12
# 接收端(指定以太网接口 192.168.0.10)
go run ./cmd/flute_receiver/main.go --cli --dest-ip 239.1.1.1 --mcast-iface 192.168.0.10注意: 多播模式下,发送端和接收端必须在同一子网或相邻子网(TTL=2)。发送端默认通过查询系统路由表(route -n get / ip route get)自动确定出口网卡;路由查询失败时会回退到 INADDR_ANY 并提示手动指定 --mcast-iface。
发送端和接收端通过不同策略选择网络接口:
| 模式 | 发送端 | 接收端 |
|---|---|---|
| 单播 | 不指定网卡—由 OS 路由表根据目标 IP 决定出口接口 | 绑定到 0.0.0.0(所有接口)—内核在所有 UP 接口上监听 |
| 多播 | 默认查路由表(route -n get / ip route get)自动确定出口接口 → IP_MULTICAST_IF 设置出口;支持 --mcast-iface 手动覆盖 |
绑定到 0.0.0.0 + INADDR_ANY 上 IP_ADD_MEMBERSHIP,内核在所有接口加入多播组 |
- 多播模式下发送端优先查路由表自动选择出口网卡;路由查询失败时回退到
INADDR_ANY并提示手动指定--mcast-iface。 - 接收端始终绑定
0.0.0.0,不主动选择网卡;多播时通过JoinMulticastGroup注册硬件过滤。
FluteGo 运行在纯 UDP/IP 之上(AF_INET + SOCK_DGRAM),不接触链路层:
| 场景 | 发送端需要对方 MAC? | 接收端需要对方 MAC? | 原因 |
|---|---|---|---|
| 单播 | 需要(静态 ARP 或 ARP 可达) | 不需要 | 以太网帧需要目标 MAC;单向信道中 ARP 请求无回复,故需手动配置静态 ARP |
| 多播 | 不需要 | 不需要 | 多播 MAC 由 IP 地址通过确定性算法算出(如 239.1.1.1 → 01:00:5E:01:01:01),无需 ARP |
关于
IP_ADD_MEMBERSHIP: 接收端通过SetsockoptIPMreq(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq)加入多播组。此系统调用的核心作用是:
- 更新网卡硬件多播过滤表,使网卡不再丢弃该组播 MAC 的帧
- 设置内核 socket 过滤规则,将匹配的多播包投递到应用层
在有 IGMP Snooping 交换机的网络环境下,内核会额外发送 IGMP Report 通知交换机;在网线直连场景(无交换机)下,IGMP Report 无接收方,但硬件过滤表已正确设置,数据仍能正常接收。
FluteGo 本身不构建或解析 IGMP 报文——该协议由操作系统内核自动处理。
| 交换机配置 | 行为 |
|---|---|
| IGMP Snooping 关闭(默认) | 组播帧作为广播帧向所有端口泛洪(flood),接收端总能收到 |
| IGMP Snooping 开启 | 交换机监听 IGMP Report 建立 MAC→端口映射,组播流量只转发到注册过的端口 |
物理介质(光纤/铜缆)不影响 IGMP 行为——IGMP 是 IP 层协议,光纤交换机处理机制与电口交换机完全相同。
-
Start receiver first
-
Then start sender
- RaptorQ 需要 ≥K 个不同符号才能解码一个 chunk,K = ceil(chunkSize / symbolSize)。
send-redundancy-ratio控制每个 chunk 的额外符号数:totalSymbols = ceil(K × ratio)。- 当
percentage = 100/(ratio) × 100%时,发送端恰好发送 K 个基符号(无冗余),此时只要丢 1 个包就可能导致某个 chunk 解码失败。 - 推荐
ratio = 1/(packetLossRate+0.01)作为安全值:例如丢包 5% 用 ratio=1.20,丢包 10% 用 ratio=1.50。 - 实际测试中因为丢包的随机分布,有时即使理论符号数足够也可能解码失败(关键符号集中丢失)。
- 大文件(1GB+)比小文件更容易恢复成功,因为丢包分散在更多 chunk 上,每个 chunk 丢包概率更低。
# macOS Intel
GOOS=darwin GOARCH=amd64 go build -o release/flute_sender_darwin_amd64 ./cmd/flute_sender/
GOOS=darwin GOARCH=amd64 go build -o release/flute_receiver_darwin_amd64 ./cmd/flute_receiver/
# macOS Apple Silicon (M1/M2/M3/M4)
GOOS=darwin GOARCH=arm64 go build -o release/flute_sender_darwin_arm64 ./cmd/flute_sender/
GOOS=darwin GOARCH=arm64 go build -o release/flute_receiver_darwin_arm64 ./cmd/flute_receiver/
# Windows 64-bit
GOOS=windows GOARCH=amd64 go build -o release/flute_sender_windows_amd64.exe ./cmd/flute_sender/
GOOS=windows GOARCH=amd64 go build -o release/flute_receiver_windows_amd64.exe ./cmd/flute_receiver/| 平台 | GOOS | GOARCH | 输出文件名 |
|---|---|---|---|
| macOS Intel | darwin |
amd64 |
flute_sender_darwin_amd64 / flute_receiver_darwin_amd64 |
| macOS Apple Silicon (M1/M2/M3/M4) | darwin |
arm64 |
flute_sender_darwin_arm64 / flute_receiver_darwin_arm64 |
| Windows 64-bit | windows |
amd64 |
flute_sender_windows_amd64.exe / flute_receiver_windows_amd64.exe |
编译产物统一输出到 release/ 目录,方便分发。
# 直接编译(默认当前平台)
go build -o flute_sender ./cmd/flute_sender/
go build -o flute_receiver ./cmd/flute_receiver/测试环境:
- 发送端 / 接收端:同一局域网两台 Windows 主机,千兆网线直连
- 参数:
SymbolSize = 1024B,ChunkSize = 1024 symbols (1MB),MaxPacketSize = 1048B - 速率:不限速(
rateLimitMbps = 0) - 文件:
bin/test_{128,256,512,768,1024}MB.bin(随机二进制,MD5 校验通过) - 数据来源:
results/sender_performance.csv+results/transfer_stats.csv - 速率以发送端为准(接收端因异步处理存在统计偏差)
发送端性能(速率权威):
| 文件大小 | 耗时 (s) | 吞吐速率 (Mbps) | 有效速率 (Mbps) | 总发送包数 | 源符号数 | 修复符号数 |
|---|---|---|---|---|---|---|
| 128 MB | 2.314 | 474.84 | 463.97 | 131,072 | 131,072 | 0 |
| 256 MB | 4.707 | 466.92 | 456.23 | 262,144 | 262,144 | 0 |
| 512 MB | 9.717 | 452.37 | 442.01 | 524,288 | 524,288 | 0 |
| 768 MB | 14.168 | 465.37 | 454.71 | 786,432 | 786,432 | 0 |
| 1024 MB | 19.579 | 449.03 | 438.74 | 1,048,576 | 1,048,576 | 0 |
接收端统计:
| 文件大小 | 收包数 | 收包率 | 完整性 | 峰值堆内存 (MB) | GC 次数 | 状态 |
|---|---|---|---|---|---|---|
| 128 MB | 131,072 | 100.00% | 128/128 chunks | 52.3 | 47 | completed |
| 256 MB | 262,144 | 100.00% | 256/256 chunks | 52.6 | 105 | completed |
| 512 MB | 524,288 | 100.00% | 512/512 chunks | 81.6 | 200 | completed |
| 768 MB | 786,432 | 100.00% | 768/768 chunks | 22.3 | 295 | completed |
| 1024 MB | 1,048,576 | 100.00% | 1024/1024 chunks | 106.3 | 393 | completed |
发送端性能:
| 文件大小 | 耗时 (s) | 吞吐速率 (Mbps) | 有效速率 (Mbps) | 总发送包数 | 源符号数 | 修复符号数 |
|---|---|---|---|---|---|---|
| 128 MB | 2.323 | 544.18 | 462.21 | 150,784 | 131,072 | 19,712 |
| 256 MB | 4.713 | 536.47 | 455.66 | 301,568 | 262,144 | 39,424 |
| 512 MB | 10.211 | 495.20 | 420.60 | 603,136 | 524,288 | 78,848 |
| 768 MB | 14.974 | 506.54 | 430.24 | 904,704 | 786,432 | 118,272 |
| 1024 MB | 19.911 | 507.94 | 431.42 | 1,206,272 | 1,048,576 | 157,696 |
接收端统计:
| 文件大小 | 收包数 | 收包率 | 完整性 | 峰值堆内存 (MB) | GC 次数 | 状态 |
|---|---|---|---|---|---|---|
| 128 MB | 150,784 | 115.04% | 128/128 chunks | 80.1 | 48 | completed |
| 256 MB | 301,568 | 115.04% | 256/256 chunks | 38.5 | 96 | completed |
| 512 MB | 603,136 | 115.04% | 512/512 chunks | 34.4 | 188 | completed |
| 768 MB | 904,704 | 115.04% | 768/768 chunks | 53.7 | 277 | completed |
| 1024 MB | 1,206,272 | 115.04% | 1024/1024 chunks | 77.7 | 362 | completed |

