pulse

command module
v0.1.0-alpha.7 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 26, 2026 License: MulanPSL-2.0 Imports: 3 Imported by: 0

README

📡 Pulse(带宽驱动全双工 UDP 探针)

以带宽为规格,以事件为真相 —— Specify bandwidth. Measure truth.

Pulse 将目标带宽换算为整数包率(pps),驱动全双工 UDP;客户端与服务端只记录原始事件到 CSV,由 pulse merge 离线计算延迟、丢包与 Goodput,并生成 HoloWAN Recorder 兼容的 report.txt。运行时可选用类 iperf3 UDP 的周期表输出(见下文「终端周期表」)。

version go module platform transport host license


📘 术语说明

术语 说明
【pps】 packets per second,由目标带宽与 payload 大小换算得到的整数发包速率,用于定时发送。
【Goodput】 有效吞吐量(Mbps),由 merge 按实际收包数与时长统计,与声明带宽可能不同。
【HoloWAN Recorder】 HoloWAN 录制器兼容的文本报告头与周期数据行格式,便于接入既有网络仿真工具链。
【payload】 应用层 UDP 数据字节数;CLI 中的 -size 指 payload,不含 9 字节二进制包头。

⚡ 快速开始(约 5 秒)

在两个终端分别启动服务端与客户端(周期统计默认每秒一行,打在标准输出):

# 终端 1:启动服务端
./pulse server -p 5000

# 终端 2:启动客户端(使用默认参数)
./pulse client -s localhost:5000

# 合并结果(自动生成 report.txt)
./pulse merge \
  --client results/*/client.csv \
  --server results/*/server.csv

默认测试时长 10 秒,上行 1 Mbps / 下行 2 Mbps,结果存于 results/ 目录。若不需要终端周期表,可在 server / client 上加 -i 0 关闭。


📋 核心能力

  • ⏱️ 精确带宽控制:将目标带宽(如 1Mbps)转换为整数包率(pps),避免浮点调度误差
  • 📦 统一载荷大小:上下行共用 -size(payload 字节数,不含 9 字节二进制头)
  • 🕒 时间轴对齐:服务端记录的时间戳已映射到客户端时轴,可直接计算端到端延迟
  • 📊 离线分析友好merge 子命令自动读取 config.json,按分桶周期输出 HoloWAN 格式报告
  • 📟 类 iperf3 UDP 周期表client / server 支持 -i / -interval,主时长内按间隔打印 Transfer / Bitrate / Jitter / Lost/Total(详见下文);结构化日志走 stderr,表格走 stdout
  • 🔁 同一二进制server / client / merge / pcap plan|replay / version
  • 📱 跨平台支持:Linux / macOS / Windows / Android(arm64)
  • 📦 依赖:除 gopacket(PCAP 解析,读文件走纯 Go pcapgo、默认 CGO_ENABLED=0)外无其他第三方模块

💻 安装与构建

获取源码

独立仓库:

git clone https://gitcode.com/sangachy/pulse.git
cd pulse

若你在更大 monorepo 内仅使用本工具子路径,请在包含本目录 go.mod 的目录下执行下文命令(与仓库布局无关,以 go.mod 所在目录为准)。

下文所有 go build./scripts/... 命令均默认在该目录下执行。

要求
  • Go 1.22 或更高版本
构建

国内拉模块可先(与 scripts/build-release.sh 行为一致):

source scripts/go-env-aliyun.sh   # 设置 GOPROXY/GOSUMDB,可写入 shell 配置持久化
go build -trimpath -buildvcs=false -o pulse ./cmd/pulse

提示:若构建环境无 .git 目录,建议保留 -buildvcs=false
若未设置 GOPROXY 时拉取 gopacket 出现 proxy.golang.org 超时,请先执行上一段 source scripts/go-env-aliyun.shgo build / go test

PCAP 合成回放(简要)
  • pulse pcap plan:从 PCAP 生成 plans/ 下 JSON 计划;未指定双端时按 最大流自动推断 IP,手动模式须同时给 -client-endpoint / -server-endpoint(可为 IPv4IP:PORT,仅 IP 时该侧任意端口均匹配,见 docs/design-pulse.md)。
  • pulse pcap replay:按 plan 与墙钟锚点与 pulse server(默认从 plans/ 读同名文件)做双向 UDP 回放。
  • 服务端:-pcap-plan-dir 默认 plans
多平台发布(含版本注入)
# 使用默认版本 v0.1.0-alpha.2
./scripts/build-release.sh

# 指定版本(需与 git tag 一致)
VERSION=v0.1.0 ./scripts/build-release.sh

Windows 用户:

scripts\build-release.bat
仅构建 Android(arm64)
mkdir -p dist
GOOS=android GOARCH=arm64 CGO_ENABLED=0 go build -trimpath -buildvcs=false \
  -ldflags "-s -w -X gitcode.com/sangachy/pulse/internal/version.Version=v0.1.0" \
  -o dist/pulse-android-arm64 ./cmd/pulse

设计细节(START 协议、二进制包头、周期表语义)见 docs/design-pulse.md


🧪 使用指南

1. 启动服务端(必须先运行)
./pulse server -p 5000 -o results

PCAP 回放:请先将 plan JSON 放入运行目录下 plans/(或 pulse server -pcap-plan-dir DIR),再执行 pulse pcap replay;详见上文「PCAP 合成回放」与设计文档。

2. 启动客户端
# 使用默认参数(size=512, ul=1Mbps, dl=2Mbps, duration=10s)
./pulse client -s 192.168.1.100:5000 --test-id="video_call_01"

# 自定义参数
./pulse client \
  -s 192.168.1.100:5000 \
  -size 1024 \
  --ul-bandwidth 1Mbps \
  --dl-bandwidth 5Mbps \
  -duration 30s \
  --time-delta=0 \
  --test-id=video_call_01 \
  -o /data/pulse_runs

若省略 --test-id,系统自动生成唯一 ID(格式:YYYYMMDDTHHmmss_xxxxxx,如 20260306T201103_a3f91c),日志中会打印实际路径。

3. 合并分析(post-processing)
# 自动读取同目录 config.json,输出 report.txt
./pulse merge \
  --client results/video_call_01/client.csv \
  --server results/video_call_01/server.csv

# 显式指定报告路径
./pulse merge \
  --client results/video_call_01/client.csv \
  --server results/video_call_01/server.csv \
  --o-txt /tmp/report.txt \
  --o-json /tmp/summary.json

--o-json 根对象形如(note_cn 为长字符串,此处省略):

{
  "schema": "pulse.merge.summary.v2",
  "config": {
    "test_id": "video_call_01",
    "size": 1024,
    "duration_sec": 30,
    "sample_interval_sec": 0.1,
    "server_addr": "192.168.1.100:5000",
    "ul_bandwidth": "1Mbps",
    "dl_bandwidth": "2Mbps",
    "grace_period_sec": 10,
    "time_delta_ns": 0,
    "ul_interval_ns": 4194304,
    "dl_interval_ns": 2097152,
    "ul_packet_count": 3579139,
    "dl_packet_count": 7158278,
    "ul_pps": 238,
    "dl_pps": 476,
    "ul_target_mbps": 1,
    "dl_target_mbps": 2,
    "ul_actual_mbps": 0.999,
    "dl_actual_mbps": 1.998,
    "output_root": "results"
  },
  "uplink": {
    "delay_avg_ms": 12.3,
    "delay_paired_sample_count": 1000,
    "loss_percent": 0.5,
    "goodput_whole_session_mbps": 0.95,
    "packets_sent": 1000,
    "packets_recv": 995
  },
  "downlink": {
    "delay_avg_ms": 11.0,
    "delay_paired_sample_count": 998,
    "loss_percent": 0.2,
    "goodput_whole_session_mbps": 1.80,
    "packets_sent": 1000,
    "packets_recv": 998
  },
  "out_of_bucket": {
    "ul_sent_before_bucket_base": 0,
    "ul_sent_after_duration_window": 0,
    "dl_sent_before_bucket_base": 0,
    "dl_sent_after_duration_window": 0
  },
  "note_cn": "…"
}

merge 会:

  • client.csv 同目录加载 config.json
  • sample_interval_sec 分桶
  • 丢弃超窗样本(并在 stdout 报告 underflow/overflow)
  • 输出 HoloWAN 兼容的 report.txtStart / End Time 由双端 CSV 全部非空 timestamp_ns 的最小、最大值换算为本地墙钟时间;无任何时间戳时回退为执行 merge 的时刻;表头 Test Name:Duration(sec):Interval(sec):Packet Size(byte):config.jsontest_id / duration_sec / sample_interval_sec / size 一一对应。客户端写入的 config.json 含完整跑测快照(含 grace_period_sectime_delta_ns、间隔/包数/pps、目标与实际 Mbps、output_root 等);config.json 提供 server_addr 或上下行带宽字符串时,mergePacket Size(byte):Enable Reordering: 之间追加三行 Server Address:UL Bandwidth:DL Bandwidth:(其余派生字段不进 report.txt,见同目录 config.json--o-jsonconfig)。仅含上述四键的旧版 config.json 仍可 merge,且无扩展表头)

📟 终端周期表(iperf3 UDP 风格)

pulse clientpulse server 均支持在主测试时长内按固定间隔打印人类可读表(默认 1 秒一行),表头对齐 iperf3 UDP 五列:IntervalTransferBitrateJitterLost/Total Datagrams,行首 [SUM]

Transfer / Bitrate Jitter / Lost/Total
Client 本周期内 UL 发出 + DL 收到 的 payload 字节合计 仅针对 DL 入站(到达间隔相对理论节拍;丢包为期望 DL 包数 − 实收)
Server 本周期内 UL 收到 + DL 发出 的 payload 字节合计 仅针对 UL 入站
  • merge 分桶无关--sample-interval 只写入 config.json;周期表用 -i / -intervaltime.ParseDuration),0 关闭-interval 非空时覆盖 -i
  • 输出:表格 → stdoutslog 诊断 → stderr(便于重定向与脚本解析)。
  • 权威指标:延迟/丢包整场汇总仍以 pulse merge 与 CSV 为准;终端表便于运行时扫一眼。

示例(两终端对跑时各自 stdout 各有一套表;以下为示意):

[ ID] Interval           Transfer     Bitrate         Jitter    Lost/Total Datagrams
[SUM]    0.00-   1.00   sec     488 KBytes     4.00 Mbits/sec   0.050 ms  0/488 (0%)

📤 输出文件说明

每轮测试生成独立目录:{output_root}/{test_id}/

客户端生成
文件 说明
client.csv 本地事件:SENT_UL(发上行)、RECV_DL(收下行)
config.json 一次 client 跑测的完整配置快照(供 merge 与归档;含 CLI 与 schedule 派生字段)
服务端生成
文件 说明
server.csv 远端事件:RECV_UL(收上行)、SENT_DL(发下行)时间戳已映射到客户端时轴
示例:client.csv
event,seq,timestamp_ns,size
SENT_UL,0,1710662904123456789,1024
RECV_DL,0,1710662904194326789,1024
示例:server.csv
event,seq,timestamp_ns,size
RECV_UL,0,1710662904155606789,1024
SENT_DL,0,1710662904190000000,1024
RECV_UL,1,,1024          # 空时间戳 = 丢包
示例:report.txt(HoloWAN 格式)
HoloWAN Recorder File (Pulse)
Test Name: "video_call_01"
Duration(sec): 30
Start Time: 2026-03-20 14:50:32
End Time: 2026-03-20 14:51:02
Interval(sec): 0.1
Packet Size(byte): 1024
Server Address: "192.168.1.100:5000"
UL Bandwidth: "1Mbps"
DL Bandwidth: "2Mbps"
Enable Reordering: True
Contents: Delay1(ms),Loss1(%),Bandwidth1(Mbps),Delay2(ms),Loss2(%),Bandwidth2(Mbps)
Switch: 1,1,1,1,1,1
------------------------------------------------
-0.952341,0.000000,0.999424,1.128756,0.081967,0.998605
...
  • Delay1/Loss1/Bandwidth1上行(客户端 → 服务端)
  • Delay2/Loss2/Bandwidth2下行(服务端 → 客户端)

🔬 指标计算逻辑(merge 阶段)

指标 计算方式
Delay1(上行延迟) T_server.RECV_UL − T_client.SENT_UL
Delay2(下行延迟) T_client.RECV_DL − T_server.SENT_DL
Loss1(上行丢包率) (UL_SENT − UL_RECV) / UL_SENT
Loss2(下行丢包率) (DL_SENT − DL_RECV) / DL_SENT
Goodput 整场(终端输出 / --o-json (UL_RECV 或 DL_RECV 总包数 × size × 8) / (duration_sec × 1e6)duration_secsize 来自 client.csv 同目录 config.json
Goodput 分桶report.txt 每行 Bandwidth*) 上行:(该桶内 UL_RECV 数 × size × 8) / (sample_interval_sec × 1e6);下行同理用 DL_RECV;sample_interval_sec 来自 config.json

所有延迟基于配对成功的包计算算术平均值;Goodput 与目标带宽无关。report.txt 表头 Start/End Time秒精度YYYY-MM-DD HH:MM:SS),与常见 HoloWAN / playback 解析习惯一致。Test Name: 对应 config.jsontest_id(或与目录名兜底一致),与 Duration(sec):Interval(sec):Packet Size(byte): 同为「词首大写」风格;常见 HoloWAN 解析会将 Test Name 规范为 test_name


⚙️ 命令行参数详解

pulse server
参数 必选 默认值 说明
-p 监听端口
-o results 输出根目录
-i 1s 周期表间隔,0 关闭(同 -interval
-interval (空) 非空时覆盖 -i
pulse client
参数 必选 默认值 说明
-s 服务端地址 IP:PORT
-size 512 payload 字节数(不含头部)
--ul-bandwidth 1Mbps 上行目标带宽
--dl-bandwidth 2Mbps 下行目标带宽
-duration 10s 测试时长
--sample-interval 100ms 分桶采样间隔(写入 config.json,供 merge
-i 1s 周期表间隔,0 关闭(同 -interval
-interval (空) 非空时覆盖 -i
--time-delta 0 客户端相对服务端的时钟偏移(纳秒)
--test-id 自动生成 测试标识符
-o results 输出根目录

带宽单位:支持 bpsKbpsMbps(不区分大小写),简写 k/m 等价于 Kbps/Mbps;纯数字视为 bps

pulse merge
参数 必选 说明
--client 客户端 CSV 路径
--server 服务端 CSV 路径
--o-txt 报告文本输出路径(默认同目录 report.txt
--o-json 汇总 JSON(schema: pulse.merge.summary.v2):configuplinkdownlinkout_of_bucketnote_cn,见上文示例
pulse version

输出一行:pulse vX.Y.Z(与 Git tag 和构建注入一致)


📡 协议与内部机制

首包(START 消息)

客户端发送 JSON 首包启动测试:

{
  "cmd": "start",
  "test_id": "video_call_01",
  "dl_size": 1024,
  "dl_interval_ns": 1639344,
  "ul_interval_ns": 8196721,
  "duration_s": 30,
  "time_delta_ns": 123456789,
  "ul_packet_count": 3660,
  "dl_packet_count": 18300
}
后续数据包

采用紧凑二进制格式(含魔数、序列号、方向、payload),详见 docs/design-pulse.md


🧮 带宽 → 整数包率(pps)算法

给定目标带宽 B(bps)和 payload 大小 S(字节):

步骤 含义 公式(与实现一致,纯文本可读)
1 理论包率(浮点) pps_theoretical = B / (8 * S)
2 实际包率(四舍五入为整数) pps = round(pps_theoretical)
3 实际可达带宽(bps) B_actual = pps * 8 * S
4 发包间隔(纳秒) interval_ns = 10^9 / pps(Go 中为整数除法,见 internal/schedule

⚠️ 若 pps = 0(如带宽过低),客户端将报错退出。


🛠️ 开发与测试

# 运行全部测试
go test ./...

# 仅运行单元测试(跳过集成)
go test -short ./...
  • 可选集成数据TestDouyinPCAPPlanReplayMerge(根包)读取 testdata/douyin.pcap;未放置该文件时测试会 自动 Skip,不影响 go test ./...
  • Git LFStestdata/*.pcap.gitattributes 中配置为 LFS(体积较大)。克隆后若需跑该集成测试,请安装 Git LFS 并在本仓库执行 git lfs installgit lfs pull,或将自有抓包放到 testdata/douyin.pcap

📦 依赖

  • 零第三方依赖:仅使用 Go 标准库(net, flag, encoding/csv, log/slog, time 等)

📜 License

木兰宽松许可证第二版(Mulan Permissive Software License, Version 2)
© 2024–2026 sangachy
详见 LICENSE

再分发:须向接收方提供许可证全文副本(通常随包保留根目录 LICENSE),并保留源码中的版权与免责声明。各 .go 源文件头部已含 Mulan PSL v2 建议声明(英文)。


Pulse — No symmetry assumptions. No hidden defaults. Just precise, mergeable events.

Documentation

Overview

Package main 为 Pulse 探针安装入口,用于支持直接 go install 安装

Source Files

  • main.go

Directories

Path Synopsis
cmd
pulse command
Package main 为 Pulse 探针入口:server / client / merge 共用同一二进制。
Package main 为 Pulse 探针入口:server / client / merge 共用同一二进制。
internal
bandwidth
Package bandwidth 解析 README 约定的带宽字符串为 bps(比特每秒)。
Package bandwidth 解析 README 约定的带宽字符串为 bps(比特每秒)。
client
Package client 实现 Pulse UDP 客户端。
Package client 实现 Pulse UDP 客户端。
cmd
Package cmd 包含 Pulse 探针的核心命令逻辑
Package cmd 包含 Pulse 探针的核心命令逻辑
compare
Package compare 实现 pulse 测试结果对比功能
Package compare 实现 pulse 测试结果对比功能
logcsv
Package logcsv 读写 Pulse 事件 CSV(event,seq,timestamp_ns,size)。
Package logcsv 读写 Pulse 事件 CSV(event,seq,timestamp_ns,size)。
merge
Package merge 根据双端 CSV 与 README 公式汇总指标。
Package merge 根据双端 CSV 与 README 公式汇总指标。
pcapplan
Package pcapplan 从 PCAP 文件生成 replay plan(IPv4 UDP/TCP)。
Package pcapplan 从 PCAP 文件生成 replay plan(IPv4 UDP/TCP)。
pcapreplay
Package pcapreplay 按 plan 与墙钟锚点执行客户端侧 PCAP 回放。
Package pcapreplay 按 plan 与墙钟锚点执行客户端侧 PCAP 回放。
planpath
Package planpath 解析客户端 plan 路径与服务端 plan 文件名安全校验。
Package planpath 解析客户端 plan 路径与服务端 plan 文件名安全校验。
replayplan
Package replayplan 定义 PCAP 回放的 JSON plan 读写与派生统计。
Package replayplan 定义 PCAP 回放的 JSON plan 读写与派生统计。
report
Package report 生成 HoloWAN Recorder 风格占位报告(六元组由 merge 或人工填写)。
Package report 生成 HoloWAN Recorder 风格占位报告(六元组由 merge 或人工填写)。
schedule
Package schedule 实现 README 中的整数 pps、interval_ns、实际带宽与总包数。
Package schedule 实现 README 中的整数 pps、interval_ns、实际带宽与总包数。
server
Package server 实现 Pulse UDP 服务端。
Package server 实现 Pulse UDP 服务端。
sessionmeta
Package sessionmeta 负责测试配置快照的读写。
Package sessionmeta 负责测试配置快照的读写。
statsprint
Package statsprint 提供与 iperf3 UDP 周期表相近的终端定宽输出。
Package statsprint 提供与 iperf3 UDP 周期表相近的终端定宽输出。
statwindow
Package statwindow 提供周期统计用的线程安全字节与入站到达时间累积。
Package statwindow 提供周期统计用的线程安全字节与入站到达时间累积。
version
Package version 提供单一版本号来源,与 Go modules 的 tag(如 v0.1.0-alpha.2)语义对齐。
Package version 提供单一版本号来源,与 Go modules 的 tag(如 v0.1.0-alpha.2)语义对齐。

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL