{"code":1,"msg":"成功","time":"1789816292","data":{"title":"RyanMqtt+LWIP+大吞吐导致的socket资源泄漏问题","content":"## 问题\r\n\r\n- 最近使用RyanMqtt进行大量数据传输，数据量大概最大并发应该在5-10KB\/s，运行一段时间后发现设备将彻底断联，接入串口打印内存信息和网络状态发现，Socket泄露和内存莫名低至即KB。\r\n\r\n## 实机复现链\r\n\r\n1. MQTT 服务端把 TCP 接收窗口压到 1024 B，连接后停止读数据。\r\n2. 设备以 100 ms 采集配置持续发送，`send()` 进入 lwIP `NETCONN_WRITE`。\r\n3. 服务端发 FIN，MQTT 接收线程读到 EOF，进入断连事件并关闭同一 socket。\r\n4. `LWIP_NETCONN_FULLDUPLEX=0` 时，`lwip_netconn_do_delconn()` 发现 netconn 仍在 `NETCONN_WRITE`，返回 `ERR_INPROGRESS`。\r\n5. `lwip_close()` 因此在 `free_socket()` 之前返回 -1；实机日志中映射为 errno 122。\r\n6. RT-Thread SAL 无论底层关闭成功与否，都执行 `socket_delete()` 和 `fd_release()`；MQTT 层也将自己的 fd 设为 -1。底层 lwIP socket\/netconn 从此不可达。\r\n7. 测到 13 次 errno 122，`mbox` 最多 33 行、`sem` 最多 32 行，之后出现 33 次 `socket连接失败: -253`。\r\n8. 此时已建立连接可以暂时存活；一旦该连接断开，重连无法创建新 socket\r\n\r\n## 最小修复\r\n\r\n在 `RyanMqttEventDisconnected` 内，设置断连状态后，使用已有 `sendLock` 包住`platformNetworkClose()`。这使关闭等待当前发送结束，不给接收加锁，正常收发仍并行。\r\n\r\n没有开启 `LWIP_NETCONN_FULLDUPLEX`：lwIP 2.1.2 明确要求同时实现`LWIP_NETCONN_SEM_PER_THREAD` 及线程信号量生命周期\r\n\r\n## 回归结果\r\n\r\n- 同一小窗口+FIN 场景连续 30 轮，关闭失败 0，socket -253 为 0，没有邮箱\/信号量累计。\r\n- 压测结束后：可用堆恢复到 90192 B，资源对象回到基线。","updatetime":"2026-09-17 09:20:12","author":"金卡啦喂"}}