解决MySql布尔型新旧版本兼容问题,采用枚举来表示布尔型的数据表。由正向工程赋值
|
# 裸 Socket 层性能测试报告
> 测试范围:**不含协议编码器**的裸 Socket 收发链路——TCP/UDP × 单包单帧/单包多帧(粘包)× 包大小(32B~1MB)× 并发 × 客户端接收方式;**吞吐与分配以服务端为口径(优化目标),往返延迟为客户端观察**。
> 关联报告:[网络库编解码器Echo性能测试报告](/NewLife/X/Blob/v12/Doc/性能/网络库编解码器Echo性能测试报告.md)(协议层)、[内存分配与拷贝成本报告](/NewLife/X/Blob/v12/Doc/性能/../内存分配与拷贝成本报告.md)。
> 数据版本:**v3.2(2026-10-09 重构后复测)**——服务端口径(吞吐/分配)、并发与尺寸扫描、带宽比特率单位;本次为接收环/会话重构后的回归复测,**各档与 v3.1 持平、无回归**,UDP 64KB 峰值 134.5→138.9 Gbps(+3.2%)、TCP 1KB 并发峰值 13.7→14.5 Gbps;v3.1 优化项与本次复测结论见第七节;工具 `Benchmark/NetLoadTest`(`run-matrix.ps1` 一键复现)。
> **v3.3(同日)**:UDP 接收改 `ReceiveFromAsync`——每包分配 **216→104 B**、每包 CPU **-1.3 µs**、1KB 高并发包率 **+18.8%**(见第七节)。
> **v3.4(同日)**:定位 TCP 大包档受**内核接收窗口**限制,新增 `SocketSetting.ReceiveBufferSize`(内核接收缓冲,默认 0=不改);负载/高延迟下 1MB 报文 +25%,空闲回环无收益(见第七节)。
> **v3.5(同日)**:多进程加压实验证明**服务端远未饱和**(TCP 1KB 1.48 Mpps 仅 1.31 核、UDP 1KB 600 kpps 约 2.0 核),修正"单进程接收环饱和"表述(见 5.2)。
> **v3.6(同日)**:**NativeAOT vs JIT 对比**——AOT 全面小幅领先(吞吐 +4~11%、往返 P50 -12%、分配更低),启动无差异(见第八节)。
> **v3.7(同日)**:**延迟尾部分位归因**——并发扫描证明 RTT ≈ 并发数/吞吐(Little 定律)⇒ 延迟主体是排队;无载下库仅比裸 Socket 多 2.4 µs 且尾延迟更优(见 4.3)。
## 一、核心结论
> **口径**:服务端与客户端分离进程;**吞吐与分配 = 服务端口径**(吞吐取服务端接收稳态;分配取服务端进程每消息托管分配),**延迟 = 客户端观察 RTT**(往返时间只能由发起方测);服务端接收始终是异步接收环(SAEA)。单位:带宽 = 比特率(1 Gbps = 10⁹ bit/s),包率 = kpps / Mpps。
### 表 1 吞吐(服务端稳态,各档取最优并发)
| 协议 | 场景 | 最优并发 | 带宽 | 包率 | 帧率(粘包) | 服务端分配 B/msg |
|---|---|---:|---:|---:|---:|---:|
| TCP | 单帧 32B | 8C | 0.36 Gbps | 1.40 Mpps | — | 0.12 |
| TCP | 单帧 1KB | 16C | **14.5 Gbps** | 1.77 Mpps | — | 0.12 |
| TCP | 单帧 64KB | 4C * | **53.1 Gbps** | 101 kpps | — | 1.1 |
| TCP | 单帧 1MB | 8C | 32.2 Gbps | 3.8 kpps | — | 264 |
| TCP | 粘包 24B 帧(64KB 包) | 8C | 40.0 Gbps | — | **208 M帧/s** | 1.6 |
| UDP | 单帧 32B | 4C | 0.07 Gbps | 281 kpps | — | 216 |
| UDP | 单帧 256B | 4C | 0.60 Gbps | 294 kpps | — | 216 |
| UDP | 单帧 1KB | 32C | 4.12 Gbps | **503 kpps** | — | 216 |
| UDP | 单帧 4KB | 4C | 8.69 Gbps | 265 kpps | — | 216 |
| UDP | 单帧 16KB | 8C | 40.4 Gbps | 308 kpps | — | 216 |
| UDP | 单帧 64KB(IP 分片) | 32C | **138.9 Gbps** | 265 kpps | — | 216 |
| UDP | 粘包 24B 帧(64KB 包) | 4C | 81.2 Gbps | — | **417 M帧/s** | 216 |
> * TCP 大包跨运行波动大:64KB 本次矩阵 4 并发单跑 44.6 Gbps,5 次复测 49.2/58.1/53.1/58.0/41.0(中位 53.1,表内取复测中位)、8 并发 5 次复测 42.0/35.1/33.4/41.1/35.4(中位 35.4);1KB 峰值 16 并发 14.5 Gbps 亦为单跑高值,5 次复测 13.1/12.1/14.1/15.3/11.9(中位 13.1)。
### 表 2 往返延迟(客户端观察,µs)
| 协议 | 包大小 | 并发 | 接收方式 | P50 | P95 | P99 | 服务端分配 B/msg |
|---|---|---:|---|---:|---:|---:|---:|
| TCP | 32B | 4 | 同步 | 49.2 | 65.0 | 76.8 | 1.1 |
| TCP | 1KB | 4 | 同步 / 异步 / 事件 | 46.7 / 58.2 / 50.3 | 63.6 / 78.2 / 70.3 | 73.9 / 92.2 / 82.1 | 1.0-1.3 |
| TCP | 64KB | 4 | 同步 / 异步 / 事件 | 103.2 / 85.6 / 97.5 | 137.5 / 103.4 / 122.3 | 167 / 116 / 143 | 1.8-2.2 |
| TCP | 1MB | 4 | 同步 | 1509.8 | 2593.2 | 3191 | 235 |
| TCP | 1KB | 64 | 同步 / 异步 / 事件 | 290.7 / 271.4 / 265.5 | 381.0 / 366.7 / 328.2 | 425 / 463 / 368 | 2.3-2.4 |
| TCP | 64KB | 64 | 同步 / 异步 / 事件 | 1632.5 / 1375.1 / 1379.0 | 3212.8 / 2918.7 / 2789.8 | 4014 / 3756 / 3560 | 11.7-14.2 |
| UDP | 32B | 1 | 同步 | 39.5 | 52.3 | 88 | 258 |
| UDP | 1KB | 1 | 同步 / 事件 | 40.1 / 48.9 | 54.0 / 64.3 | 90 / 99 | 258-259 |
| UDP | 64KB | 1 | 同步 | 60.7 | 92.0 | 129 | 260 |
### 浓缩结论
- **TCP 小包由每包固定成本主导**:32B 与 1KB 包率同档(≈1.4-1.8 Mpps);1KB 带宽从 1 并发 0.62 Gbps 升至 16 并发 **14.5 Gbps**,32/64 并发回落(13.4/13.2)——拐点在 16 并发。**注意**:这**不是**服务端饱和(见 5.2 加压实验:服务端仅用 0.75-1.31 核),而是客户端每包 7.5 µs 的内核发送成本与回环栈上限。
- **TCP 大包进每字节成本区间**:64KB 4 并发复测中位 **53.1 Gbps(≈6.3 GiB/s)**、8 并发中位 35.4;1MB 档 32.2 Gbps。
- **UDP 包率与并发强相关**:1KB 从 4C 的 273 kpps 升至 32C 的 **503 kpps**;64KB 从 4C 80.6 Gbps 升至 32C 的 **138.9 Gbps**(v3.1 134.5,+3.2%)。
- **UDP 服务端每消息分配恒定 216 B(TCP 近零)**:v3.1 已把每包字符串键查找开销消除(330→216,GC 频率 ~-40%,见第七节);剩余为运行时端点对象开销(SAEA 完成回调就地更新并随会话保留,每包必须新建 IPEndPoint)。
- **延迟**:TCP 1KB 4C P50 ≈47µs、64C ≈266-291µs;事件接收尾延迟最好(64C P99 368µs vs 同步 425µs);UDP P50 40-61µs;1MB 大包往返 P50 ≈1.5ms。**延迟主体是排队**(RTT ≈ 并发/吞吐,见 4.3),库在无载下的自身开销仅 2.4 µs。
- **分配**:TCP 服务端 0.08-5.5 B/msg(GC 全零;1MB 档 264 B/msg 已归因为约 1 MB/s 背景分配,非每包成本,见 5.1);UDP 服务端 216 B/msg(每 ~6.3 万包一次 Gen0);UDP 客户端发送 41.5→**0.4 B/msg**(v3.1 自动连接,见第七节)。
## 二、测试方法
### 测试环境
```text
复测日期:2026-10-09(v3.2,与 v3.1 同机同口径)
Windows 10 (10.0.19045.6456/22H2)
Intel Core i9-10900K CPU 3.70GHz, 1 CPU, 20 逻辑核心 / 10 物理核心
.NET SDK 10.0.401
Runtime: .NET 10.0.12, X64 RyuJIT x86-64-v3(Server GC)
网络:loopback(127.0.0.1),服务端与客户端分离进程
```
### 工具与口径(`Benchmark/NetLoadTest`)
- 一键复现:`Benchmark/NetLoadTest/run-matrix.ps1`(全矩阵约 20 分钟)输出 `results.md / results.json`;单场景直连 `NetLoadTest.exe`;
- **分离进程**:服务端独立进程(`--server`,静默 3 秒输出 `STEADY` 稳态中位数:带宽/包率/帧率/服务端分配/GC,然后自动退出),客户端 `--remote` 连接;
- **三种测量模式**:`--oneway` 单向上行(服务端只计数,测纯接收)/`pipeline` 回显流水线/`roundtrip` 逐包往返(采样 P50/P95/P99);
- **客户端接收方式** `--recvmode`:`sync` 同步拉取/`asyncpull` 异步拉取(`ReceiveAsync`)/`event` 事件接收(`Received` 回调);
- 口径要素:预热 2s + 窗口 10s;测量前发**预热流量**(触发服务端冷启动 JIT 与池化初始化,避免首样本计入百毫秒级冷启动);服务端接收始终是异步接收环(SAEA);`--frame 24` 模拟粘包(24B 逻辑帧);UDP 单包钳制 65507 字节;带宽用比特率(1 Gbps = 10⁹ bit/s ≈ 119 MiB/s)。
- **复现前提(重要)**:矩阵的绝对数值**只在安静窗口内可比**。本机长期存在非本报告的背景负载(另一会话的 `java` 约 1.1 核、Roslyn 编译服务器 `VBCSCompiler` 突发可达 **4 核**),叠加回环内核栈对 CPU 调度的敏感性,同场景背靠背复测离散度可达 **3 倍**(2026-10-10 实测 `tcp-64KB-c4` 三次为 9.84 / 12.65 / 28.31 Gbps,同期历史高值 44.6 Gbps)。因此:
1. **不要跨时段比较绝对值**——判断优化效果必须用**交替配对 A/B**(同窗口内交替跑对照与实验组、多轮取中位、区间不重叠)或**同环境因果实验**;
2. 跑批前先确认 `VBCSCompiler` / `java` 等外来进程已静默,否则得到的全表不能用于替换报告数据。
## 三、吞吐(服务端接收稳态)
### 3.1 TCP
**尺寸曲线(8 客户端)**
| 包大小 | 带宽 | 包率 | 服务端分配 B/msg | GC |
|---:|---:|---:|---:|---:|
| 32B | 0.36 Gbps | 1.40 Mpps | 0.12 | 0/0/0 |
| 1KB | 12.1 Gbps * | 1.47 Mpps | 0.08 | 0/0/0 |
| 64KB | 37.7 Gbps * | 72 kpps | 1.7 | 0/0/0 |
| 1MB | 32.2 Gbps | 3.8 kpps | 264 | 1/1/1 |
**并发扫描(1KB 与 64KB)**
| 并发 | 1KB 带宽 / 包率 | 64KB 带宽 |
|---:|---:|---:|
| 1 | 0.62 Gbps / 76 kpps | 16.8 Gbps |
| 4 | 7.05 Gbps / 861 kpps | 44.6 Gbps *(复测中位 53.1) |
| 8 | 12.1 Gbps * / 1.47 Mpps | 37.7 Gbps *(复测中位 35.4) |
| 16 | **14.5 Gbps** / 1.77 Mpps | 32.5 Gbps |
| 32 | 13.4 Gbps / 1.63 Mpps | 29.8 Gbps |
| 64 | 13.2 Gbps / 1.61 Mpps | — |
> * 8 并发两档跨运行波动较大(1KB:11.9-15.3,中位 13.1;64KB:33.4-42.0,中位 35.4);64KB 4 并发复测中位 53.1(41.0-58.1)。
- 小包拐点在 **16 并发**(≈14.5 Gbps),再增加不再提升——**不是接收环饱和**(加压实测服务端仅 0.75-1.31 核),而是客户端每包 7.5 µs 的内核发送成本与回环栈上限,见 5.2;
- 64KB 大包 4 并发即达峰(复测中位 ≈53 Gbps、6.3 GiB/s),更多并发反而回落;
- 服务端分配除 1MB 档外全部 ≈0(GC 零次):接收路径「轮末裁决 + 句柄回挂」已达近零分配。
### 3.2 UDP
**尺寸曲线(4 客户端)**
| 包大小 | 带宽 | 包率 | 服务端分配 B/msg |
|---:|---:|---:|---:|
| 32B | 0.07 Gbps | 281 kpps | 216 |
| 256B | 0.60 Gbps | 294 kpps | 216 |
| 1KB | 2.24 Gbps | 273 kpps | 216 |
| 4KB | 8.69 Gbps | 265 kpps | 216 |
| 16KB | 30.8 Gbps | 235 kpps | 216 |
| 64KB(IP 分片) | 80.6 Gbps | 154 kpps | 216 |
**并发扫描(1KB 与 64KB)**
| 并发 | 1KB 带宽 / 包率 | 64KB 带宽 |
|---:|---:|---:|
| 1 | 0.77 Gbps / 94 kpps | 25.4 Gbps |
| 2 | 1.37 Gbps / 168 kpps | 48.7 Gbps |
| 4 | 2.24 Gbps / 273 kpps | 80.6 Gbps |
| 8 | 3.09 Gbps / 377 kpps | 98.8 Gbps |
| 16 | 3.52 Gbps / 430 kpps | **138.7 Gbps** |
| 32 | 4.12 Gbps / **503 kpps** | **138.9 Gbps** |
| 64 | 4.03 Gbps / 492 kpps | — |
**客户端连接化**(v3.1 库内置:纯客户端模式打开即 Connect 远端)
| 指标 | 旧版(SendTo) | v3.1(自动连接) |
|---|---:|---:|
| 服务端吞吐(1KB 4C / 64KB 4C) | 2.34 / 81.2 Gbps | 2.36 / 82.5 Gbps(不变) |
| 客户端分配 | 41.5 B/msg | **0.4 B/msg** |
- 未连接 UDP 发送走 `Socket.SendTo`,每包序列化 `SocketAddress`(实测 43 B/包);连接化后走 `Send`(零分配)——收益在客户端,服务端吞吐不变;
- 优化后 UDP 服务端分配恒定 **216 B/msg**(详见第七节):包率从 4C 273 kpps 提升至 32C 的 503 kpps,1KB 高并发吞吐较优化前 +20%。
### 3.3 粘包多帧(24B 逻辑帧)
| 协议 | 对齐后大包 | 帧/包 | 包率 | 帧率 | 带宽 |
|---|---:|---:|---:|---:|---:|
| TCP | 1,008 B | 42 | 1.44 Mpps | 59.0 M帧/s | 11.63 Gbps |
| TCP | 65,520 B | 2,730 | 76.4 kpps | **208 M帧/s** | 40.0 Gbps |
| UDP | 1,008 B | 42 | 270 kpps | 11.3 M帧/s | 2.18 Gbps |
| UDP | 65,496 B | 2,729 | 155 kpps | **417 M帧/s** | 81.2 Gbps |
- 帧率随大包尺寸大幅提升(固定成本被 2,700+ 帧摊薄);业务侧批量化是性价比最高的吞吐手段。
### 3.4 回显流水线(客户端接收方式对照)
| 包大小 | 接收方式 | 回显吞吐 | 带宽 | 服务端分配 | 客户端分配 |
|---:|---|---:|---:|---:|---:|
| 1KB | 同步 / 异步 / 事件 | 1.16 / 1.32 / **1.28*** M msg/s | 9.5 / 10.8 / 10.5 Gbps | 0.09-0.20 | 6.6 / 27.2 / **0.02** |
| 64KB | 同步 / 异步 / 事件 | 21.6 / **26.7*** / 21.6 k msg/s | 11.3 / **14.0*** / 11.3 Gbps | 12.4-13.3 | 158 / 559 / **1.0** |
> * 1KB 事件与 64KB 异步单跑偏低(896 MiB/s、1292 MiB/s),取 3 次复测中位(1250 MiB/s、1667 MiB/s)。
- 1KB 档三种接收方式同档(1.16-1.32 M msg/s);**客户端分配差异显著**:异步拉取状态机最高(1KB 27 B/msg、64KB 559 B/msg),事件接收近零(1KB 0.02、64KB 1.0 B/msg,见第五节)。
## 四、往返延迟(客户端观察 RTT)
> RTT 只能由发起方(客户端)观察;下列延迟含客户端路径成本,服务端处理成本见「服务端分配」列。
### 4.1 TCP
| 包大小 | 并发 | 接收方式 | P50 | P95 | P99 | max | 服务端分配 B/msg |
|---:|---:|---|---:|---:|---:|---:|---:|
| 32B | 4 | 同步 | 49.8 | 69.5 | 80.8 | 4,433 | 1.1 |
| 1KB | 4 | 同步 | 48.2 | 65.2 | 74.3 | 4,853 | 1.1 |
| 64KB | 4 | 同步 | 100.0 | 110.8 | 135.3 | 3,250 | 2.1 |
| 1MB | 4 | 同步 | 1,408.6 | 1,843.7 | 2,201.6 | 4,784 | 208 |
| 1KB | 64 | 同步 | 275.1 | 401.5 | 455.7 | 16,361 | 2.5 |
| 64KB | 64 | 同步 | 1,499.6 | 2,682.4 | 3,358.2 | 6,877 | 12.6 |
| 1KB | 4 | 异步 | 56.6 | 75.8 | 87.9 | 1,570 | 1.3 |
| 1KB | 64 | 异步 | 276.9 | 396.3 | 467.3 | 47,725 | 2.5 |
| 64KB | 4 | 异步 | 96.1 | 116.3 | 129.1 | 1,645 | 2.1 |
| 64KB | 64 | 异步 | 1,336.1 | 2,670.0 | 3,308.5 | 11,087 | 11.7 |
| 1KB | 4 | 事件 | 52.8 | 69.6 | 81.1 | 2,528 | 1.1 |
| 1KB | 64 | 事件 | 266.6 | 390.0 | 430.5 | 22,824 | 2.4 |
| 64KB | 4 | 事件 | 86.7 | 105.0 | 117.6 | 1,135 | 1.9 |
| 64KB | 64 | 事件 | 1,414.2 | 2,671.3 | 3,270.1 | 8,766 | 12.3 |
- 包大小:32B/1KB 同档(P50 ≈47-49µs,链路固定成本);64KB→86-103µs、1MB→1.5ms(带宽支配);
- 并发:4→64 使小包 P50 升至 266-291µs;64KB 大包 64 并发升至 1.38-1.63ms;
- 接收方式:低并发小包同步与事件接近(46.7 vs 50.3µs);事件接收在 64KB 与尾延迟上最优(64C P99 368µs vs 同步 425µs、异步 463µs)。
### 4.2 UDP
| 包大小 | 并发 | 接收方式 | P50 | P95 | P99 | max | 服务端分配 B/msg |
|---:|---:|---|---:|---:|---:|---:|---:|
| 32B | 1 | 同步 | 32.6 | 49.2 | 87.0 | 5,824 | 258 |
| 1KB | 1 | 同步 | 40.7 | 49.6 | 84.9 | 5,882 | 258 |
| 64KB | 1 | 同步 | 59.8 | 75.6 | 129.8 | 6,104 | 260 |
| 1KB | 1 | 事件 | 48.7 | 59.7 | 94.1 | 2,236 | 260 |
- UDP 单次往返 P50 ≈40-61µs,快于 TCP(省去连接/确认状态机开销);64KB 单包 P50 61µs(IP 分片);max 为偶发调度毛刺,低频可忽略;服务端分配 258-260 B/msg(接收+回显,较优化前 373 降 30%)。
**延迟构成**:低并发最小往返 ≈23-27µs(TCP);该数值不是 loopback 物理极限(内核单次传输 1-1.2µs),大头是**两次用户态系统调用(Send + 阻塞 Receive 唤醒)+ 线程调度 + 服务端回显链路**。分位与组分的定量归因见 4.3。
### 4.3 延迟尾部分位归因(v3.7)
> 追问:P99 是 GC 暂停造成,还是 CPU 调度排队?用三个相互独立的实验交叉验证(TCP 1KB 往返,10 s 窗口,服务端 GC 暂停取自服务端 STEADY 口径)。
**实验 A:并发扫描——RTT ≈ N/λ(Little 定律)**
```
NetLoadTest.exe --mode roundtrip --remote 127.0.0.1:<port> --clients <1..64> --size 1024 --seconds 10 --warmup 2
```
| 并发 N | 吞吐 λ (pps) | P50 | P95 | P99 | N/λ (µs) | P50 − N/λ |
|---:|---:|---:|---:|---:|---:|---:|
| 1 | 25,942 | 34.8 | 51.2 | 66.3 | 38.5 | −3.7 |
| 2 | 39,205 | 49.9 | 65.1 | 81.5 | 51.0 | −1.1 |
| 4 | 74,506 | 52.2 | 69.2 | 80.8 | 53.7 | −1.5 |
| 8 | 121,912 | 64.7 | 88.5 | 104.3 | 65.6 | −0.9 |
| 16 | 167,527 | 94.9 | 126.0 | 150.1 | 95.5 | −0.6 |
| 32 | 198,570 | 148.4 | 238.1 | 285.7 | 161.2 | −12.8 |
| 64 | 212,000 | 290.3 | 411.8 | 536.3 | 301.9 | −11.6 |
P50 与理论值 N/λ 在 1→64 并发全程吻合(绝对误差 ≤13 µs)⇒ **延迟的绝大部分是排队**(请求在接收环/线程队列中等待),而不是每包固定开销;唯一的"每包开销"是 N=1 时的 34.8 µs。
**实验 B:裸 Socket 地板对照**(单客户端 1KB 乒乓,双方阻塞 Send/Receive 且 NoDelay,30 万次 × 3 轮)
| 实现 | P50 | P95 | P99 | max | mean |
|---|---:|---:|---:|---:|---:|
| 裸 Socket | 32.3-32.5 | 45.8-46.6 | 75.7-80.5 | 7,888-8,436 | 35.4-35.7 |
| NewLife 库 | 34.8 | 51.2 | 66.3 | 2,708 | — |
- 库在无载下仅比裸 Socket 多 **2.4 µs(+7%)**——即 handler 分发 + 会话状态机 + 句柄所有权转移的全部代价;
- **库的 P99 反而更好**(66.3 vs 75.7-80.5):裸阻塞 `Receive` 需把线程从内核等待队列重新调度,而库用**预投递异步接收 + IO 完成**,唤醒路径更短;
- 裸 Socket 单跑 max 也达 7.9-8.4 ms ⇒ **毫秒级毛刺是本机 OS 调度固有**,与库无关。
**实验 C:GC 暂停量 vs 人为调度压力(判别实验)**
| 场景 | P50 | P99 | 客户端 GC 暂停总量 | 服务端 GC 暂停 |
|---|---:|---:|---:|---:|
| 1KB 4C 同步 | 50.9 | 85.1 | 4.39 ms / 10 s(0.04%) | 0.0 ms |
| 1KB 4C 同步 + 6 核人为忙等 | 68.6 | 145.1 | 5.17 ms(几乎不变) | 0.0 ms |
| 1KB 64C 同步 | 271.5 | 396.2 | 47.30 ms(0.47%) | 0.0 ms |
| 1KB 64C 事件 | 273.5 | 478.8 | **4.84 ms**(同步的 1/10) | 0.0 ms |
| 1KB 64C 异步拉取 | 315.1 | 569.0 | 104.45 ms | 0.0 ms |
- **服务端 GC 暂停恒为 0.0 ms**:与服务端远未饱和(见 5.2)一致,服务端不贡献尾延迟;
- 加 6 核 CPU 竞争而 **GC 暂停几乎不变**时,P50 +35%、P99 +70% ⇒ 尾部由 **CPU 调度排队**主导;
- 事件接收的 GC 暂停只有同步的 1/10(4.84 vs 47.30 ms),P99 却**更宽**(478.8 vs 396.2)⇒ GC 暂停量与尾延迟**不相关**。
**结论**:往返延迟 = 排队(N/λ)+ 34.8 µs 无载服务时间 + OS 调度毛刺。库自身在无载下只剩 **2.4 µs** 空间,且其尾延迟已优于裸阻塞 Socket;进一步压低 P99 只能靠减少排队深度(客户端限流、多进程分散)或改善平台调度,均不在库内。**不做**进一步的延迟优化——收益 <2.4 µs,代价是复杂度。
## 五、内存分配(服务端口径)
| 场景 | 服务端 B/msg | GC 0/1/2 | 说明 |
|---|---:|---|---|
| TCP 单帧 32B~64KB | 0.08-1.7 | 0/0/0 | 接收路径近零(轮末裁决 + 句柄回挂复用) |
| TCP 单帧 1MB | 264(非每包成本,见 5.1) | 1/1/1 | ≈1 MB/s 背景分配折算;**非缓冲池丢池**(池零借还) |
| TCP 回显(32B~64KB) | 0.09-13.3 | 0/0/0 | 接收 + 回显发送 |
| UDP 单帧(全尺寸) | **216** | 每 ~6.3 万包一次 Gen0 | 32 B 强制预置端点 + 184 B 运行时固有(见 5.1) |
| UDP 往返(接收 + 回显) | 258-260 | — | 较优化前 373 降 30% |
| TCP 客户端同步拉取往返 | 187-208 | — | 每包 `OwnerPacket + ArrayOwner` 句柄对 |
| TCP 客户端异步拉取往返 | 628-661 | — | 每 await 的 async 状态机 + Task |
| TCP 客户端事件往返 | 43-58 | — | 接收环复用句柄,近零 |
| TCP 客户端流水线(同步/异步/事件) | 6.6 / 27.2 / **0.02** | — | 1KB;事件模式零分配 |
| UDP 客户端发送(旧版 SendTo / v3.1) | 41.5 / **0.4** | — | v3.1 自动连接后走 `Send` |
**优化进展(v3.1)**
1. ✅ **UDP 服务端接收路径**(已落地):会话查找由字符串键改为**端点键缓存**——330→216 B/msg(-35%),Gen0 频率 ~-40%,UDP 高并发吞吐 +7~25%(见第七节);
2. ✅ **UDP 客户端 Connect 化**(已落地):库内置纯客户端模式自动连接,41.5→0.4 B/msg;
3. ✅ TCP 1MB 档 264 B/msg 已归因(见 5.1):**非每包成本、也非缓冲池丢池**——接收环稳态**零借还**(计数器实测),实为约 1 MB/s 的背景分配折算。
### 5.1 分配与每包 CPU 归因(v3.2 隔离实验)
为把「待专项核实」变成结论,用**一次性裸 Socket 探针**(不含 NewLife 代码、不提交)+ 临时计数器复现同一路径:
| 实验 | 配置 | 结果 |
|---|---|---|
| UDP 接收环(裸 Socket + SAEA) | `ReceiveMessageFromAsync`,每轮重投 `new IPEndPoint(Any, 0)` | **216.0 B/msg**、11.5 µs/包、578 kpps |
| 同上,仅换 `ReceiveFromAsync` | 其余不变 | **104.0 B/msg**、10.2 µs/包、**661 kpps(+14%)** |
| 同上,复用同一端点实例 | 仅做测量,库内不可用 | 184.3 B/msg(差 **31.99 ≈ 32 B**) |
| 同上,`RemoteEndPoint` 传 null | — | 抛 `ArgumentException`:运行时**强制**预置非空端点 |
| TCP 接收环(裸 Socket,1MB 缓冲) | 复用槽缓冲 / 每轮 ArrayPool 换新 | 两者均 **≈0 B/msg** |
| 纯 ArrayPool 1MB 压力 | 256 缓冲常驻 + **19.6 亿次**借还 | **0 字节**(池不丢) |
| 库接收环临时计数器 | TCP 1MB 单向稳态 | `OwnerPacket` 构造 **0 次**、"换新"分支 **0 次** |
| 裸 Socket TCP 客户端 CPU | 16 线程 × 1KB | 1.51 Mpps、**7.49 µs/包** |
| 库 TcpSession 客户端 CPU | 16 客户端 × 1KB | 1.63 Mpps、**7.47 µs/包** |
结论:
1. **UDP 216 B/msg = 32 B 强制预置端点 + 184 B 运行时固有**,库内已无剩余可去。184 B 来自运行时完成回调构造的接收结果端点,应用层无法规避;32 B 预置为运行时强制(传 null 直接抛错)。复用同一实例虽可降 32 B,但端点对象随会话长期留存,复用会把其它会话的端点改掉——**不安全,不采用**。
2. **TCP 1MB「264 B/msg」既非每包成本、也非「丢池」**:接收环稳态**零次** `OwnerPacket` 构造与"换新"(临时计数器实测),纯 ArrayPool 在 19.6 亿次借还下 0 分配。真实来源是约 **0.03-0.05% 字节量**的微量背景分配(1MB 档 ≈1 MB/s,占该档吞吐 0.02%),不在缓冲/池路径上;`B/msg` 只是把它除以低包率放大成的**度量假象**。
3. **每包 CPU 由平台决定**:服务端开销**远小于**内核侧——加压实测 TCP 1KB 在 1.48 Mpps 时仅 **1.31 核**、UDP 1KB 在 ~600 kpps 时约 **2.0 核**(见 5.2);而发送端 7.5 µs/包的内核成本由裸 Socket 与库客户端**同等承担**(7.49 vs 7.47 µs/包)。吞吐天花板因此由 **Windows loopback 内核协议栈**决定,非库内瓶颈。
4. **NoDelay 默认值经 A/B 验证正确**:同一库、同构接收回环,1KB × 8C 单向吞吐 `NoDelay=false`(Nagle 合并小包)**11.08 Gbps** vs `NoDelay=true` **6.90 Gbps**。客户端 `TcpSession.NoDelay` 默认 false 有利于吞吐,**不是缺陷**(服务器接受连接默认 `NoDelay=true` 属延迟取向,两者场景不同)。
5. **UDP 接收 API 已优化落地**(见第七节 v3.3):`ReceiveMessageFromAsync` → `ReceiveFromAsync`,每包省 **112 B** 分配、每包 CPU **-1.3 µs**;同环境配对 A/B 实测 UDP 1KB 高并发包率 **+18.8%**(区间不重叠)。代价是每包本地地址退化为绑定地址(与消息路径 `e.Local = Local.Address` 同口径;Mono/Android 分支本就如此)。
### 5.2 加压实验:服务端不是瓶颈(v3.5)
矩阵用**单个客户端进程**产生负载,而单进程客户端自身的同步发送会烧掉十余核,容易被误读成"服务端接收环饱和"。改为**多客户端进程**加压(同名场景、同环境;`run-matrix.ps1 -ClientProcs N` 已内置该能力):
| 协议 / 包大小 | 客户端进程 × 连接 | 服务端带宽 | 服务端包率 | **服务端 CPU** |
|---|---|---:|---:|---:|
| TCP 1KB | 1 × 16 | 8.01 Gbps | 977 kpps | 0.75 核 |
| TCP 1KB | 2 × 16 | 9.56 | 1.17 Mpps | 1.05 核 |
| TCP 1KB | 4 × 16 | **12.09** | **1.48 Mpps** | **1.31 核** |
| TCP 1KB | 8 × 8 | 10.41 | 1.27 Mpps | 1.16 核 |
| UDP 1KB | 1 × 32 | 4.92 | 600 kpps | 2.04 核 |
| UDP 1KB | 2 × 32 | 4.46 | 544 kpps | 2.35 核 |
| UDP 1KB | 4 × 32 | 4.47 | 545 kpps | 2.11 核 |
| UDP 1KB | 8 × 16 | 4.52 | 552 kpps | 2.23 核 |
结论:
1. **服务端远未饱和**:TCP 1KB 在 1.48 Mpps 时仅用 **1.31 核**(20 核机的 6.5%);UDP 1KB 在 ~550-600 kpps 时约 **2.0-2.35 核**。
2. **加大客户端进程数不再提升**:TCP 从 1→4 进程提升 8.01→12.09 Gbps(+51%),8 进程回落;UDP 在 1 进程时即达 600 kpps,加进程反而略降。上限来自 **Windows 回环内核栈 + 客户端同步发送成本**(发送端 7.5 µs/包,裸 Socket 与库客户端一致,见 5.1)。
3. 因此 **"单进程接收环饱和"的说法不成立**(§3.1 原表述已修正);本机可测的 TCP 小包上限 ≈1.5 Mpps / ≈12-14 Gbps 属**平台上限**,服务端还剩约 18 核余量。
4. 同理修正早期**单点 CPU 采样**给出的"UDP 服务端 13-17 µs/包":该采样在机器带 3-4 核背景负载期间取得,与本次加压实测(~2 核 @600 kpps ≈ 3.4 µs/包)相差数倍,**以后者为准**。每包 CPU 的可靠说法是:**服务端开销远小于内核侧**。
## 六、已知限制
- **UDP 无流控**:发送端超过服务端消费能力必然丢包(灌包过载场景),业务需自行限速;调大 `UdpServer.MaxAsync` 可增大接收环并行度(实测对包率上限无提升,1KB 极限约 500 kpps);
- **UDP 服务端仍有恒定 216 B/msg**(原 330):为 .NET SAEA 完成回调的端点对象开销——运行时就地更新 `RemoteEndPoint` 且对象随会话保留,每轮接收必须新建 `IPEndPoint`,应用层无法安全规避(复用于重置会改到其它会话的端点)。**隔离实验证据**(见 5.1):裸 Socket 同构接收环 216.2 B/msg,与库内一致;其中 32 B 来自运行时**强制要求**预置的非空端点(传 null 直接抛 `ArgumentException`),184 B 为运行时固有;复用实例可降至 184.3 B/msg 但会破坏端点归属,不采用;
- **TCP 1MB 档 264 B/msg 已归因**:**非每包成本,也非缓冲池丢池**——接收环稳态零 `OwnerPacket` 构造/零"换新"(计数器实测),纯 ArrayPool 19.6 亿次借还 0 分配;实为约 1 MB/s(占该档吞吐 0.02%)的**背景分配折算**,属把背景分配摊到包数上的度量假象(见 5.1);
- **UDP 每包本地地址 = 服务器绑定地址**:接收环走 `ReceiveFromAsync`(v3.3 优化),不再读取每包包信息;多宿服务器绑 `Any` 时 `e.Local` 为 `0.0.0.0` 而非实际到包地址(与消息路径 `e.Local = Local.Address` 同口径,契约由 `UdpLocalAddress_FromServerBinding` 用例钉住);
- **每包 CPU 为平台固有**:加压实测服务端开销远小于内核侧(TCP 1KB 1.48 Mpps 仅 ~1.31 核、UDP 1KB ~600 kpps 约 ~2.0 核,见 5.2),吞吐天花板由压测客户端同步发送 + Windows loopback 内核协议栈决定,非库内瓶颈;
- **TCP 大包吞吐受内核接收窗口限制**:发送侧已按报文大小自动放大发送缓冲,接收侧此前始终用系统默认(Windows 约 64KB);带宽延迟积较大(高负载 / 高延迟链路)时窗口成为瓶颈,可用 `SocketSetting.ReceiveBufferSize` 显式放大(默认 0 不改),代价是每连接的内核内存(4MB × 1 万连接 = 40GB);
- **`UdpSession` 不实现 `INetSession`**:`NetServer.Received` 的 sender 在 UDP 下为 `UdpSession`(仅 `ISocketSession`),`s is INetSession` 分支不命中,写通用代码时注意;
- **延迟尾部不可由库内消除**:无载下库仅比裸 Socket 多 2.4 µs,其余延迟为排队(N/λ)与 OS 调度毛刺(毫秒级 max 在裸 Socket 同样出现),见 4.3。
## 七、优化记录与复测(v3.1 → v3.2)
| 优化项 | 实现 | 效果(复测) |
|---|---|---|
| UDP 会话查找去字符串键 | `SessionCollection` 新增端点键缓存(`ConcurrentDictionary<IPEndPoint>`;未命中回退字符串键,创建/移除/清理各路径同步维护并做值校验) | 服务端分配 **330→216 B/msg(-35%)**,Gen0 频率 ~-40%;UDP 高并发吞吐 +7~25%(1KB 16C 404→494 kpps、64C 499 kpps;64KB 8C 94→110-122 Gbps、32C 126→134.5 Gbps) |
| UDP 客户端自动连接 | 纯客户端模式(本地端口自动分配 + 远端为单播地址)打开即 `Connect` 远端;广播/组播/指定本地端口的双角色实例保持 SendTo 语义 | 客户端发送 **41.5→0.4 B/msg**;服务端吞吐不变(2.34→2.36 Gbps 同档) |
| 接收环并行度实验 | `MaxAsync` ×4(51 槽位)对照实验 | 包率无变化 → 槽位数不是 UDP 包率上限的瓶颈;保持默认 CPU×1.6 |
| **UDP 接收改 ReceiveFromAsync** | `UdpServer.OnReceiveAsync` 由 `ReceiveMessageFromAsync` 改为 `ReceiveFromAsync`;本地地址改由新增虚方法 `GetReceiveLocalAddress`(`UdpServer` 取 `Local.Address`)提供 | 每包分配 **216→104 B(-52%)**、每包 CPU **-1.3 µs**、**UDP 1KB 高并发包率 +18.8%**(同环境配对 A/B 3 次取中位,区间不重叠:468k→556k pps);UDP 64KB 大包档落在环境噪声内(对照档抖动 ±40%),无明确变化 |
| **TCP 内核接收缓冲旋钮** | 新增 `SocketSetting.ReceiveBufferSize`(0=不改,默认行为与内存占用均不变),在客户端连接与服务端接受连接处应用;`NetLoadTest` 加 `--rcvbuf` 便于复现 | TCP 大包档受**内核接收窗口**限制(发送侧按报文自动调优,接收侧此前无旋钮)。负载/高延迟条件下 1MB 报文 8C 中位 **16.74→20.96 Gbps(+25%)**;早期负载更重时 64KB +33%、1MB +94%;**空闲回环下 ±0%**(系统自动调优已足够)——收益取决于带宽延迟积 |
**剩余 216 B/msg 的成因**:经 .NET 运行时源码确认,SAEA 完成回调会**就地更新** `RemoteEndPoint` 对象(`EndPoint.Create` 语义),且该对象随接收结果成为会话的远程端点被长期保留——每轮接收必须使用新的 `IPEndPoint`;复用同一实例重置会把其它会话的端点改掉。该开销在应用层已无安全优化空间。
**验证**:新增单元测试 `UdpServerCreateSessionEndPointCache`(同端点复用/销毁后重建)、`UdpClientAutoConnectRemote`(自动连接+收发)、`UdpServerNoAutoConnectForBroadcastAndLocalPort`(广播/双角色不连接);UDP 相关 32 用例全绿;TCP 路径不受影响(复测同档)。
**v3.2(2026-10-09)重构后回归复测**:接收环/会话重构(句柄借出即挂槽、关闭重开契约收窄等)后全矩阵复测 61 场景,并对波动档位补充 5 次复测取中位——**各档与 v3.1 持平、无回归**;UDP 64KB 峰值 134.5→138.9 Gbps(+3.2%)、TCP 1KB 并发峰值 13.7→14.5 Gbps;分配(TCP 近零 / UDP 恒定 216 B/msg)与延迟同档。原始数据:`Benchmark/NetLoadTest/results/20261009-200337`。
**v3.2 深挖(归因收口)**:对三项遗留/疑点做隔离实验(见 5.1)——① **不存在"丢池"**:接收环稳态零 `OwnerPacket` 构造/零"换新",纯 ArrayPool 19.6 亿次借还 0 分配;TCP 1MB 264 B/msg 实为约 1 MB/s 背景分配的**度量假象**;② UDP 216 B/msg = 32 B 运行时强制预置端点 + 184 B 运行时固有,无安全优化空间;③ NoDelay 默认值经 A/B 验证**有益于吞吐**,非缺陷。**发送侧对照**:裸 Socket 客户端 7.49 µs/包 vs 库客户端 7.47 µs/包,库发送路径零额外开销;每包 CPU 归口 Windows loopback 内核协议栈。**本轮唯一可落地优化**:UDP 接收改 `ReceiveFromAsync`(每包省 112 B、包率 +14%),已按「本地地址取 `Local.Address`」方案落地,见下。
**v3.3(2026-10-09)UDP 接收 API 优化**:`UdpServer.OnReceiveAsync` 统一改走 `ReceiveFromAsync`(原仅 Mono/Android 分支才走),本地地址由新增虚方法 `GetReceiveLocalAddress` 提供(`UdpServer` 返回 `Local.Address`)。收益:每包分配 **216→104 B(-52%)**、每包 CPU **-1.3 µs**、UDP 1KB 高并发包率 **+18.8%**(468k→556k pps,同环境配对 A/B 3 次中位,区间不重叠)。代价:多宿服务器绑 `Any` 时 `e.Local` 由「实际到包地址」变为绑定地址(与消息路径 `e.Local = Local.Address` 同口径);契约由新用例 `UdpLocalAddress_FromServerBinding` 钉住,并做「退回旧实现即变红」的负向验证;UDP 相关 62 用例全绿。
**测试环境说明**:本轮复测期间机器另有约 3-4 核背景负载(对照档 `tcp-64KB-c4` 抖动达 ±40%),故 §三/§五 表格仍为 v3.2(当日空闲时)数据,UDP 档绝对量在负载下偏低;建议在空闲机器上重跑 `run-matrix.ps1` 刷新全表。
**v3.4(2026-10-09)TCP 内核接收缓冲**:定位 TCP 大包档「包率仅 ~80 kpps、1MB 档仅 4 kpps」的成因——**不是** CPU 或库内开销(服务端 1KB 档仅 0.58 µs/包),而是**接收窗口**卡住带宽延迟积:发送侧 `TuneSendBufferSize` 会按报文大小自动放大发送缓冲,接收侧却始终用系统默认(Windows 约 64KB)。用 NewLife 自身栈做因果实验(同一环境内对比):置 SO_RCVBUF=4MB 后 1MB 报文 8C 吞吐中位 **16.74→20.96 Gbps(+25%)**;更早、机器负载更重时同一对比为 64KB **+33%**、1MB **+94%**。
**重要局限**:机器转闲后同一对比回到 **±0%**——Windows 的 SO_RCVBUF 自动调优在空闲回环下已足够,显式设置只在「负载或链路延迟使 RTT 增大、BDP 超过默认窗口」时才见效。故本项做成**显式旋钮**(默认 0 = 不改,零行为变化、零内存开销),**不**默认放大(4MB × 1 万连接 = 40GB 内核内存)。验证:新增用例 `TcpReceiveBufferSize_AppliedToBothEnds`(两端套接字均带上设置值);`NetLoadTest` 加 `--rcvbuf` 便于复现。
**v3.5(2026-10-09)加压复核**:用多客户端进程加压(见 5.2)证明服务端**远未饱和**——TCP 1KB 在 1.48 Mpps 时仅用 1.31 核、UDP 1KB 在 ~600 kpps 时约 2.0 核;1→4 客户端进程使 TCP 从 8.01 提升到 12.09 Gbps(+51%),继续加进程不再提升。据此**修正**两处早期表述:① §3.1「小包拐点=单进程接收环饱和」不成立,拐点是客户端/回环栈上限;② 早期单点 CPU 采样给出的「UDP 服务端 13-17 µs/包」与加压实测不符(前者在带 3-4 核背景负载期间取得),已改为以加压实测为准。
## 八、NativeAOT 与 JIT 性能对比(v3.6,2026-10-09)
用**同一份源码**分别以 JIT(CoreCLR)与 NativeAOT 发布压测工具,在**同一时段交替配对**(JIT/AOT 轮转,抵消机器背景负载漂移):
- JIT:`dotnet build Benchmark/NetLoadTest -c Release` → `bin/Release/net10.0/NetLoadTest.exe`
- AOT:`dotnet publish Benchmark/NetLoadTestAot -c Release -r win-x64 -o out-aot` → 原生单文件 **9.50 MB**
**吞吐(各 4 轮取中位;本机另有 3-4 核背景负载,单轮抖动可达 ±40%,故只报中位并注明轮数)**
| 场景 | JIT | AOT | 变化 |
|---|---:|---:|---:|
| TCP 1KB 单向 8C | 9.01 Gbps / 1,099,964 pkt/s | **9.55 / 1,166,254** | **+6.0%** |
| UDP 1KB 单向 32C | 4.88 / 595,463 | **5.09 / 621,872** | **+4.3%** |
| TCP 1KB 往返 4C | 0.62 / 75,258 | **0.69 / 84,075** | **+11.3%** |
**延迟与分配**
| 指标 | JIT | AOT | 说明 |
|---|---|---|---|
| 往返 P50(4 轮原始) | 52 / 54.6 / 54.9 / 49.4 µs | 64.8 / 46.6 / 46.0 / 47.7 µs | 中位 53.7 → **47.2 µs(-12%)**;AOT 首轮偏高属冷启动 |
| TCP 1KB 往返 每包分配 | 1.10-1.48 B/msg | **0.60-0.94 B/msg** | AOT 分配更低 |
| TCP 1KB 单向 每包分配 | 0.17 | **0.11** | 两者都近零 |
| UDP 1KB 单向 每包分配 | 109.6 | 106.5 | 两者都 ≈ 运行时固有的 ~104 B/msg(v3.3 优化后) |
| 启动到可服务 | 204-241 ms | 230-240 ms | **无差异** |
| 单文件体积 | 0.15 MB(apphost,依赖共享运行时) | 9.50 MB | AOT 自带运行时 |
**结论**
1. **AOT 全面小幅领先**:三档吞吐 +4~11%、往返 P50 低约 12%、每包分配更低(近零档 0.17→0.11 B/msg)。三个方向一致,不是噪声偏向。
2. **启动无优势**:本场景启动耗时由进程创建与 NewLife 配置初始化主导,"免 JIT"收益不明显;AOT 的价值在这里主要是**部署形态**(单文件、无运行时依赖、可上 AOT 平台)与内存,而非启动。
3. **网络栈热路径无 AOT 风险**:1.5 Mpps 级收发、SAEA 接收环、对象池、`Pool.StringBuilder` 在 AOT 下全部正常,未触碰到反射/动态代码依赖。
4. 顺带修掉一处 AOT 不兼容:压测工具末尾的 `SUMMARY:` 原用 `JsonSerializer.Serialize`(反射式),NativeAOT 默认禁用反射式序列化会直接抛异常;改为手写序列化后 AOT 产物可正常输出汇总,ILC 的 IL2026/IL3050 告警清零。
5. **口径提醒**:偶数轮次 + 单轮 ±40% 抖动下,**小差异(<5%)不可当作定论**;本表的 +4~11% 属方向一致但幅度有限,若要更严结论需在空闲机器上加大轮次。
## 复现命令
```bash
# 全矩阵一键跑批(约 20 分钟;-Quick 冒烟 / -SkipBuild 跳过编译 / -Only 正则过滤)
pwsh -File Benchmark/NetLoadTest/run-matrix.ps1
# 多客户端进程加压(突破单进程客户端 CPU 上限,压出服务端真实余量;见 5.2)
pwsh -File Benchmark/NetLoadTest/run-matrix.ps1 -Only "tcp-1KB" -ClientProcs 4
# NativeAOT 发布与对比(同一份源码;AOT 工程见 Benchmark/NetLoadTestAot)
dotnet publish Benchmark/NetLoadTestAot -c Release -r win-x64 -o out-aot
out-aot/NetLoadTest.exe --server --port 7789 --oneway
# 单场景:分离进程单向吞吐(服务端独立进程 + 客户端只发不收;服务端 STEADY 含分配/GC)
Benchmark/NetLoadTest/bin/Release/net10.0/NetLoadTest.exe --server --port 7789 --oneway
Benchmark/NetLoadTest/bin/Release/net10.0/NetLoadTest.exe --remote 127.0.0.1:7789 --clients 8 --size 65536 --seconds 10 --warmup 2 --oneway
# 单场景:往返延迟(客户端接收方式可选 sync|asyncpull|event)
Benchmark/NetLoadTest/bin/Release/net10.0/NetLoadTest.exe --server --port 7789 --size 1024
Benchmark/NetLoadTest/bin/Release/net10.0/NetLoadTest.exe --remote 127.0.0.1:7789 --mode roundtrip --clients 4 --size 1024 --seconds 10 --recvmode event
# 粘包口径(24B 逻辑帧)与 UDP 连接化实验
Benchmark/NetLoadTest/bin/Release/net10.0/NetLoadTest.exe --remote 127.0.0.1:7789 --clients 8 --size 65536 --seconds 10 --oneway --frame 24
Benchmark/NetLoadTest/bin/Release/net10.0/NetLoadTest.exe --remote 127.0.0.1:7789 --udp --clients 4 --size 1024 --seconds 10 --oneway --udpconnect
```
|