docs: record v1.1.0 low-RAM TCP backpressure design
This commit is contained in:
@@ -184,6 +184,68 @@ EN,LPORT,RIP,RPORT,UART
|
||||
2. 统一受 `LINK[idx]` 配置驱动
|
||||
3. 由调度层决定实例与 UART 的数据交换路径
|
||||
|
||||
### 6.4 `v1.1.0` 低 RAM TCP 背压修复
|
||||
|
||||
`v1.1.0` 起,`TCP -> UART` 路径补充如下实现约束,用于解决“TCP 接收过快、UART 发送过慢时本地缓存被冲垮”的问题,同时尽量不新增静态 RAM:
|
||||
|
||||
1. 继续复用 `tcp_server` / `tcp_client` 现有 `RX ring`,不为每个连接新增独立的大块 pending payload 缓冲。
|
||||
2. `tcp_server_on_recv()` / `tcp_client_on_recv()` 不再在回调内立即 `tcp_recved()`。
|
||||
3. lwIP 交来的 `pbuf` 在回调中通过 `pbuf_ref()` 转为应用持有,再释放回调上下文的原始引用;后续由应用在主循环中继续把数据泵入 `RX ring`,最终在消费完成后释放。
|
||||
4. 当 `RX ring` 暂时装不下时,剩余数据保留在 `hold_pbuf + hold_offset` 中,等待主循环下一轮继续搬运。
|
||||
5. 只有当数据真正从 `TCP RX ring` 被 `drop` 掉,也就是已经被下游 `UART` 接收进入发送路径时,才调用 `tcp_recved()` 释放 TCP 接收窗口。
|
||||
|
||||
这样做的效果是:
|
||||
|
||||
1. `UART` 慢时,TCP 窗口不会继续无条件放大。
|
||||
2. 对端发送速度会被 lwIP 接收窗口自然压制。
|
||||
3. 修复点建立在已有 ring 与主循环调度之上,不引入 `FreeRTOS` 或新的大块静态缓存。
|
||||
|
||||
#### RAW 与 MUX 的分流规则
|
||||
|
||||
在 `v1.1.0` 中,`TCP` 侧拿到的都是纯 payload,因此 `TCP` 背压逻辑在 `RAW` 与 `MUX` 两种模式下共用到 `UART commit` 之前:
|
||||
|
||||
1. `RAW` 模式:
|
||||
- 主循环先查看 `uart_trans_tx_free()`
|
||||
- 再按 `min(tcp_available, tx_free, APP_TCP_TO_UART_CHUNK_SIZE)` 从 TCP ring `peek`
|
||||
- `uart_trans_write()` 实际写入多少,就 `drop + tcp_recved` 多少
|
||||
2. `MUX` 模式:
|
||||
- `TCP` payload 本身不带帧头尾
|
||||
- 只有当 `UART TX free >= payload_len + 6` 时,才在栈上临时编码一帧并一次性写入 `UART TX ring`
|
||||
- 只有整帧成功入队后,才按原始 payload 长度执行 `drop + tcp_recved`
|
||||
|
||||
该设计保证:
|
||||
|
||||
1. `RAW` 模式允许流式逐步提交
|
||||
2. `MUX` 模式保持“单个 UART 输出帧必须完整入队”的语义
|
||||
3. `TCP` 接收窗口始终以真实下游消费进度为准,而不是以“回调里已经 memcpy 到本地”作为提交点
|
||||
|
||||
#### RAM 与 chunk 策略
|
||||
|
||||
为给新增的 `hold_pbuf / hold_offset` 状态字段让位,并进一步降低单轮转发压力,`v1.1.0` 同步采用以下策略:
|
||||
|
||||
1. 新增 `APP_TCP_TO_UART_CHUNK_SIZE = 128`
|
||||
2. `TCP_SERVER_RX_BUFFER_SIZE` 从 `512` 调整为 `480`
|
||||
3. `TCP_CLIENT_RX_BUFFER_SIZE` 从 `512` 调整为 `480`
|
||||
|
||||
设计意图:
|
||||
|
||||
1. 利用更小的单次转发块提升主循环调度颗粒度
|
||||
2. 让 `MUX` 模式下 `payload + 6` 更容易完整进入 `UART TX ring`
|
||||
3. 在静态 RAM 已接近上限时,为少量新状态字段回收空间
|
||||
|
||||
#### 构建基线
|
||||
|
||||
`v1.1.0` 以 `MDK-ARM/TCP2UART.uvprojx` 的 `TCP2UART` Target 为构建验收基线。
|
||||
|
||||
当前一次通过的参考结果:
|
||||
|
||||
1. `errors = 0`
|
||||
2. `warnings = 0`
|
||||
3. `flash_bytes = 56544`
|
||||
4. `ram_bytes = 20376`
|
||||
|
||||
该结果说明修复后工程仍满足 `STM32F103R8T6` 的 `20KB RAM` 上限,但余量已经很小;后续若继续增加功能,应优先考虑复用现有缓冲与状态,而不是增加新的静态大数组。
|
||||
|
||||
## 七、主循环实现方向
|
||||
|
||||
主循环仍保持裸机轮询风格:
|
||||
|
||||
Reference in New Issue
Block a user