nnbcccscdscdsc 4b95d26f13 feat:扩展了结构化日志输出
- 补充了传输层观测指标
  - 增加了 UDP 丢包相关统计
  - README 也同步更新了字段口径
2026-03-17 20:53:43 +08:00
2026-03-17 20:53:43 +08:00
2026-03-17 19:58:15 +08:00

OmniSocket

OmniSocket 当前包含 3 个核心程序:

  • omni_peer
  • omni_hub
  • omni_bridge

三者统一支持 tcp | udp | kcp 三种传输协议。

构建

本地构建:

make

生成文件:

  • build/omni_peer
  • build/omni_hub
  • build/omni_bridge

Jetson 场景常用 ARM64 交叉编译:

make arm64

生成文件:

  • build/arm64/omni_peer
  • build/arm64/omni_hub
  • build/arm64/omni_bridge

程序说明

omni_peer

omni_peer 支持两种工作模式:

  • hub 模式:连接 hubbridge
  • direct 模式:peer 之间直接互连

常见用途:

  • 发送文本命令
  • 发送文件
  • 接收文件

omni_hub

omni_hub 是中心注册与转发节点,通常部署在公网服务器或中心网络位置。

主要职责:

  • 维护 client_id -> session
  • 转发 peer 之间的 bind / tunnel / status

omni_bridge

omni_bridge 是桥接节点,用于将远端 peer 接入上游 hub

主要职责:

  • 上游连接 hub
  • 下游监听本地入口供 peer 接入
  • 适用于 A <-> C <-> D <-> B 这类桥接链路

当前限制:

  • 一个 bridge 仅支持一个下游 peer
  • 下游 peer-i 必须与 bridge -i 保持一致
  • 上下游必须使用同一种协议,不支持协议转换
  • 当前实现更接近“单下游、单身份桥接”,而不是通用多租户中继

角色说明

  • A:本地电脑
  • BJetson
  • C:公网 Hub 服务器
  • D:公网 Bridge 服务器

下面示例中的 <proto> 可替换为 tcpudpkcp

说明:

  • 以下 omni_peer 示例统一采用长连接交互模式
  • 启动后连接会保持,不再使用“传输一次后自动退出”的一次性写法
  • 文本和文件传输通过终端中的交互命令完成
  • 若启动命令中使用了 -m-F,程序会执行启动动作模式,而不是进入当前 README 使用的交互模式

常用参数与命令

分类 写法 含义
启动参数 -i <client_id> 当前 peer 的逻辑身份。Hub 会根据这个 ID 记录 client_id -> session 映射,例如 -i pc 表示“我是 pc”-i jetson 表示“我是 jetson”。
启动参数 -b <peer_id> 启动后默认绑定的目标 peer。例如 -b jetson 表示后续直接输入 send ...put ... 时,默认发给 jetson
启动参数 -d <peer_id> 启动动作模式下的显式目标。通常与 -m-F 配合使用,表示把启动时的那条消息或那个文件直接发给指定目标。
启动参数 -o <output_file> 本地接收文件时的落盘路径。收到文件后会写入当前机器上的这个路径,例如 -o /tmp/from_pc.bin
交互命令 bind <peer_id> 将默认目标切换到指定 peer,后续 sendput 默认发给它。
交互命令 send <text> 向当前默认目标发送一条文本消息。
交互命令 say <peer_id> <text> 向指定 peer 发送一条文本消息,不修改当前默认目标。
交互命令 put <file> 将当前机器上的文件发送给当前默认目标。
交互命令 push <peer_id> <file> 将当前机器上的文件发送给指定 peer,不修改当前默认目标。
交互命令 show 显示当前本地状态,例如 client_id、当前绑定目标和输出路径。
交互命令 quit 退出当前 omni_peer 进程。

场景 1点对点直传

A <-> B

B 端监听:

./build/omni_peer -M direct -p <proto> -L 9001 -i jetson -o /tmp/from_pc.bin

A 端连接:

./build/omni_peer -M direct -p <proto> -H <B_IP> -P 9001 -i pc -b jetson -o /tmp/from_jetson.bin

连接建立后,可在 A 端输入:

send start
put /tmp/input.bin

如需反向 B -> A,可在 B 端输入:

put /path/to/file.bin

场景 2通过 Hub 中转

A <-> C <-> B

C 端启动 Hub

  • C 维护着一张 client_id -> session 映射表,用于记录谁是 pc、谁是 jetson,并据此转发 bind / tunnel / status
./build/omni_hub -p <proto> -P 9002

B 端连接 Hub

./build/omni_peer -p <proto> -H <C_IP> -P 9002 -i jetson -o /tmp/from_pc.bin

A 端连接 Hub

./build/omni_peer -p <proto> -H <C_IP> -P 9002 -i pc -b jetson -o /tmp/from_jetson.bin

连接建立后,可在 A 端输入:

send start
put /tmp/input.bin

如需反向 B -> A,可在 B 端输入:

bind pc
put /path/to/file.bin

场景 3通过 Bridge 桥接

A <-> C <-> D <-> B

C 端启动 Hub

  • C 仍然维护 client_id -> session 映射表A 以 pc 注册到 CBridge 以 jetson 这个逻辑身份注册到 C
./build/omni_hub -p <proto> -P 9003

D 端启动 Bridge

./build/omni_bridge -p <proto> -H <C_IP> -P 9003 -i jetson -L 9004

B 端连接 Bridge

./build/omni_peer -p <proto> -H <D_IP> -P 9004 -i jetson -o /tmp/from_pc.bin

A 端连接 Hub

./build/omni_peer -p <proto> -H <C_IP> -P 9003 -i pc -b jetson -o /tmp/from_jetson.bin

连接建立后,可在 A 端输入:

send start
put /tmp/input.bin

如需反向 B -> A,可在 B 端输入:

bind pc
put /path/to/file.bin

说明:

  • 该场景已经实现 A -> C -> D -> BB -> D -> C -> A 的桥接转发
  • 但当前 bridge 仍是单下游、单身份模型,不是完整的多节点桥接网络

日志与指标

输出位置

  • 终端文本日志:默认输出到 stderr,格式为 key=value
  • 结构化日志:默认追加到当前工作目录下的 omni_logs.jsonl
  • 性能快照统一写在 component="perf" 的 JSONL 记录里
  • 终端里会额外出现 component=perf_udp_loss 文本行;同一批 UDP 丢包字段已经合并写进对应的 component="perf" JSONL 行
  • 周期性性能快照大约每 1s 打一次;进程退出时会再打一条 tag="final"

当前文档口径

下面这些说法要以当前实现为准,不要再按旧文档理解:

  • processing / queue / transmission / propagation / end_to_end 都是“当前实现下的本地观测值或估算值”,不是严格意义上的物理链路精确测量值。
  • processing_* 当前表示本地应用层处理耗时,主要来自文件分片封装、接收端写盘等路径;它不是“某一块硬件 CPU 的完整开销画像”。
  • queue_*transmission_* 是基于当前吞吐和缓冲/队列状态反推出来的估算值。进程空转时间很长、样本很小或者当前速率很低时,这两个值可能明显偏大。
  • propagation_* 当前来自 min_rtt_ms / 2 的估算;如果当前协议没有 RTT 样本,这组字段就是 0
  • end_to_end_* 当前只在“最终接收文件的 peer”上有值来源是发送端分片里的 origin_ts_ms。发送端、Hub、Bridge 一般是 0
  • UDP 丢包统计只在 UDP 文件接收侧 peer 上有值UDP 发送侧、Hub、Bridge 不会产出这组汇总。
  • udp_retrans 字段当前还没有实现应用层 UDP 重传统计,所以现在始终是 0
  • TCP/KCP 当前记录的是重传次数/重传字节/累计发送分片,不直接记录“重传频率”这个单独字段。
  • send_buffer_pct_* / recv_buffer_pct_* 是占用率风格的指标,但不保证永远严格落在 0-100;尤其 KCP 等待队列超过窗口时,理论上可以大于 100
  • send_call_* / recv_call_* / proto_* / processing_* 有时会是 0,常见原因不是没统计,而是当前时间分辨率是毫秒,很多本地操作小于 1ms

基础与吞吐字段

文档含义 JSONL 字段 单位 当前语义 什么时候有值 / 为什么会是 0
时间戳 ts_ms ms 这条日志写出的单调时间戳 始终有值
日志分类 level / component / tag - component="perf" 表示性能快照,tag 常见为 peer_transport_sendpeer_transport_recvfinal 始终有值
身份上下文 app / proto / mode / role / self_id - 程序名、协议、模式、角色、逻辑 ID hubself_id 为空是正常的
运行时长 elapsed_ms ms 当前进程从启动到本次快照的时长 始终有值
累计发送字节 bytes_sent bytes 当前进程累计发送的协议帧总字节 无发送时为 0
累计接收字节 bytes_recv bytes 当前进程累计接收的协议帧总字节 无接收时为 0
发送次数 send_count count 当前进程累计发送帧次数 无发送时为 0
接收次数 recv_count count 当前进程累计接收帧次数 无接收时为 0
瞬时发送带宽 tx_current_mbps Mbps 最近一个统计窗口内的发送速率 当前窗口没流量时为 0
瞬时接收带宽 rx_current_mbps Mbps 最近一个统计窗口内的接收速率 当前窗口没流量时为 0
平均发送带宽 tx_avg_mbps Mbps 进程启动到当前的平均发送速率 从未发送时为 0
平均接收带宽 rx_avg_mbps Mbps 进程启动到当前的平均接收速率 从未接收时为 0
传输进度字节 progress_bytes bytes 当前文件传输已完成字节数 没有文件传输时为 0
总工作量 total_work_bytes bytes 当前文件总大小 没有文件传输时为 0
传输进度百分比 progress_pct % progress_bytes / total_work_bytes * 100 没有文件传输时为 0

调用耗时与延迟字段

文档含义 JSONL 字段 单位 当前语义 什么时候有值 / 为什么会是 0
应用层发送调用 send_call_last_ms / send_call_min_ms / send_call_max_ms / send_call_avg_ms ms peer_transport_send() 调用耗时 没有发送,或每次发送都小于 1ms 时可能为 0
应用层接收调用 recv_call_last_ms / recv_call_min_ms / recv_call_max_ms / recv_call_avg_ms ms peer_transport_next_event() 接收调用耗时 没有接收,或每次接收都小于 1ms 时可能为 0
协议层发送耗时 proto_send_avg_ms ms TCP/UDP/KCP 实际 send 路径耗时 EWMA 发送很快且小于 1ms 时常为 0
协议层接收耗时 proto_recv_avg_ms ms TCP/UDP/KCP 实际 recv 路径耗时 EWMA 接收很快且小于 1ms 时常为 0
本地处理耗时 processing_avg_ms / processing_min_ms / processing_max_ms ms 当前进程内的分片封装、写盘等本地处理耗时 仅在文件发送/接收路径上采样;操作太快时可能为 0
排队延迟估算 queue_avg_ms / queue_min_ms / queue_max_ms ms 根据发送/接收队列字节数和当前速率估算 没有队列样本时为 0;长空转后可能偏大
传输延迟估算 transmission_avg_ms / transmission_min_ms / transmission_max_ms ms 根据当前速率估算“这些字节推上链路需要多久” 没有流量样本时为 0;小样本/低速率时可能偏大
传播延迟估算 propagation_avg_ms / propagation_min_ms / propagation_max_ms ms 基于 min_rtt_ms / 2 的估算 当前协议没有 RTT 样本时为 0
端到端延迟 end_to_end_avg_ms / end_to_end_min_ms / end_to_end_max_ms ms 发送端分片 origin_ts_ms 到接收端处理时刻的差值 只在最终接收文件的 peer 上有值;发送端 / Hub / Bridge 多数为 0

可靠性字段

文档含义 JSONL 字段 单位 当前语义 什么时候有值 / 为什么会是 0
TCP 重传次数 tcp_retrans count 内核 TCP_INFO 的累计重传次数 仅 TCP 有值;未重传或非 TCP 时为 0
TCP 数据段数 tcp_data_segs_out count TCP 累计发送数据段数 仅 TCP 有值;非 TCP 时为 0
TCP 发送字节 tcp_data_bytes_sent bytes TCP 累计发送数据字节 仅 TCP 有值;非 TCP 时为 0
TCP 重传字节 tcp_retrans_bytes bytes TCP 累计重传字节 仅 TCP 有值;未重传或非 TCP 时为 0
UDP 重传次数 udp_retrans count 预留字段,当前未实现 当前始终为 0
KCP 重传次数 kcp_retrans count KCP 内部累计重传分片数 仅 KCP 有值;未重传或非 KCP 时为 0
KCP 数据分片数 kcp_data_segs_out count KCP 累计发送分片数 仅 KCP 有值;非 KCP 时为 0
KCP 发送字节 kcp_data_bytes_sent bytes KCP 累计发送分片字节 仅 KCP 有值;非 KCP 时为 0
KCP 重传字节 kcp_retrans_bytes bytes KCP 累计重传字节 仅 KCP 有值;未重传或非 KCP 时为 0
UDP 预期分片数 udp_expected_chunks count UDP 文件接收端预期应收到的总分片数 仅 UDP 文件接收侧 peer 有值;其他角色为 0
UDP 实收分片数 udp_received_chunks count UDP 文件接收端实际收到的唯一分片数 仅 UDP 文件接收侧 peer 有值;其他角色为 0
UDP 丢失分片数 udp_lost_chunks count 根据 seq 推断的缺失分片数 完整收到时为 0;非 UDP 接收侧也为 0
UDP 丢包率 udp_loss_rate_pct % udp_lost_chunks / udp_expected_chunks * 100 完整收到时为 0;非 UDP 接收侧也为 0
UDP 连续丢包区间数 udp_loss_burst_count count 丢包区间个数 无丢包时为 0
UDP 最大连续丢包长度 udp_loss_burst_max_len count 单个丢包区间的最大长度 无丢包时为 0
UDP 丢包区间摘要 udp_loss_ranges csv string 例如 4-6,9,12-13 无丢包时为空串
UDP 丢失序号样本 udp_loss_seq_sample csv string 最多记录一部分缺失 seq 样本 无丢包时为空串
UDP 接收窗口分布 udp_recv_window_dist csv string window_id:count,例如 0:3,1:28 仅 UDP 接收侧有值;没有样本时为空串

资源与算法字段

文档含义 JSONL 字段 单位 当前语义 什么时候有值 / 为什么会是 0
发送缓冲区占用 send_buffer_pct_last / send_buffer_pct_avg / send_buffer_pct_max % 风格值 Socket 或 KCP 发送队列占用率样本 没有缓冲采样时为 0KCP 拥塞时可能大于 100
接收缓冲区占用 recv_buffer_pct_last / recv_buffer_pct_avg / recv_buffer_pct_max % 风格值 Socket 或 KCP 接收队列占用率样本 没有缓冲采样时为 0
拥塞窗口 cwnd_last / cwnd_avg / cwnd_max 协议窗口大小 TCP/KCP 当前拥塞窗口样本 UDP 没有拥塞窗口,因此为 0
RTT last_rtt_ms / min_rtt_ms / max_rtt_ms ms TCP TCP_INFO 或 KCP rx_srtt 的 RTT 样本 UDP 当前没有 RTT 探测,因此为 0

实测样本

以下值来自本仓库当前实现的本地回环测试,仅用于说明“字段已经能落到 JSONL 且当前名字是什么”,不是固定性能指标。

样本 关键字段 实测值
TCP 点对点直传发送端 progress_pct / cwnd_last / last_rtt_ms / tcp_data_bytes_sent 100 / 10 / 1 / 287984
UDP Hub 中转接收端 progress_pct / udp_expected_chunks / udp_received_chunks / udp_lost_chunks / udp_recv_window_dist 100 / 3 / 3 / 0 / 0:3
KCP Bridge 桥接节点 cwnd_last / last_rtt_ms / kcp_data_bytes_sent / queue_avg_ms 2 / 7 / 265 / 33991.342083
KCP 最终接收端 progress_pct / end_to_end_avg_ms / cwnd_last 100 / 121.333333 / 2

为什么有些字段“存在但没有值”

情况 典型字段 说明
协议不适用 tcp_* 出现在 UDP/KCPkcp_* 出现在 TCP/UDPcwnd_* 出现在 UDP 字段统一保留,便于同一份 JSONL 脚本处理;不适用的协议就写 0
还没实现 udp_retrans 现在没有应用层 UDP 重传,所以这个字段只是预留
当前角色不产出 udp_expected_chunksudp_loss_*end_to_end_* UDP 丢包统计只在最终接收文件的 UDP peer 上有值;end_to_end_* 也主要只在最终接收端有值
没有采样到 RTT last_rtt_mspropagation_* UDP 当前没有 RTT 探针TCP/KCP 只有在拿到对应协议样本后才有值
时间分辨率太粗 send_call_*proto_send_avg_msprocessing_* 当前很多路径按毫秒计时,本地回环下大量操作小于 1ms,所以会显示 0
当前没有任务 progress_* 只注册但没有文件传输时,这组字段自然是 0
Description
OmniSocket 是一款基于纯 C 语言开发的高性能网络传输工具库。项目深度集成 TCP、UDP 及 KCP 协议栈,专为嵌入式(树莓派 ARM)与服务器(Linux x86)跨平台通信设计
Readme 416 KiB
Languages
C 98.7%
Makefile 0.9%
Shell 0.4%