当前位置: 首页 > news >正文

lwIP WebSocket 客户端 TCP PCB 泄漏问题分析与解决

        在嵌入式开发中,使用 lwIP 实现 WebSocket 客户端时,偶尔会遇到反复连接导致 TCP PCB(Protocol Control Block)泄漏,最终连接数达到上限(如 4)后无法再建立新连接的问题。本文将结合实际案例,分析问题原因并给出彻底解决方案。

问题现象

        设备端 WebSocket 客户端反复连接服务器,运行一段时间后,发现无法再建立新连接。通过调试 lwIP,发现 TCP PCB 数量不断增加,达到最大值后,后续连接全部失败。

#define MEMP_NUM_TCP_PCB                4

原因分析

        lwIP 的 TCP PCB 用于管理每个 TCP 连接的状态。正常情况下,连接关闭后 PCB 会被释放。但在实际代码中,WebSocket 客户端反复连接时,旧的 PCB 没有被及时释放,导致 PCB 泄漏。主要原因有:

  • 连接关闭时未主动调用 altcp_close 或 altcp_abort 彻底释放 PCB。
  • 新连接初始化前未检查并释放旧 PCB。

解决方案

         1.关闭连接时彻底释放 PCB,在 wsock_close() 函数中,主动调用 altcp_close,如失败则调用 altcp_abort

 if (pws->pcb) {
altcp_arg(pws->pcb, NULL);
altcp_recv(pws->pcb, NULL);
altcp_err(pws->pcb, NULL);
altcp_poll(pws->pcb, NULL, 0);
altcp_sent(pws->pcb, NULL);
if (altcp_close(pws->pcb) != ERR_OK) {
altcp_abort(pws->pcb);
close_err = ERR_ABRT;
}
pws->pcb = NULL;
}

        2. 修改lwipopts.h的LWIP_SOCKET宏定义:

 #define LWIP_SOCKET                     0

总结

        问题的根本原因是同事一开始没有改LWIP_SOCKET这个宏,默认为1,出现连接失败会自动调用wsock_close()导致出现HardFault_handler,然后他把这段释放处理屏蔽了,能正常使用,但又导致TCP PCB未能正确释放。

#define LWIP_SOCKET                     1

 

    if(pws->pcb)

    {

        altcp_arg(pws->pcb, NULL);

        altcp_recv(pws->pcb, NULL);

        altcp_err(pws->pcb, NULL);

        altcp_poll(pws->pcb, NULL, 0);

        altcp_sent(pws->pcb, NULL);

        // 主动关闭连接,彻底释放PCB资源

        // if(altcp_close(pws->pcb) != ERR_OK)

        // {

        //     altcp_abort(pws->pcb);

        //     close_err = ERR_ABRT;

        // }

        pws->pcb = NULL;

    }

        因为 lwIP WebSocket 客户端是基于 lwIP 的 TCP/ALTCP 原生 API 和 PCB 机制实现的,而不是基于 Socket API,LWIP_SOCKET 1 使能了 Socket API,导致 lwIP 内部在连接失败时自动调用 wsock_close(),而如果 PCB 或相关资源未正确初始化或已被释放,wsock_close() 内部访问空指针或非法内存就会触发 HardFault。

        正确的做法就是只需要修改lwipopts.h的LWIP_SOCKET宏定义为0,websocket_client.c源文件不需要修改:

#define LWIP_SOCKET                     0

 

http://www.dtcms.com/a/284730.html

相关文章:

  • 时空大数据:数字时代的“时空罗盘“
  • 工业一体机在3C家电自动化生产中的实践
  • CAN总线抗干扰实战:用差分传输解决地线电压漂移问题
  • Spring 多模块配置国际化,MessageSource只能加载一个文件
  • springboot 整合spring-kafka客户端:SASL_SSL+PLAINTEXT方式
  • mongodb 入门级别操作
  • Unity VR多人手术模拟恢复2:客户端移动同步问题分析与解决方案
  • jeecgbootvue3使用封装组件注意事项
  • 学习 Flutter (四):玩安卓项目实战 - 中
  • 【WPF】WPF 自定义控件之依赖属性
  • Matlab2025a软件安装|详细安装步骤➕安装文件|附下载文件
  • Mask2Former,分割新范式
  • Kafka 控制器(Controller)详解:架构、原理与实战
  • Python23 —— 标准库(time库)
  • c++列表初始化
  • Dijkstra 算法求解多种操作
  • Stone3D教程:免编码制作在线家居生活用品展示应用
  • 【初始Java】
  • mysql中where字段的类型转换
  • (转)Kubernetes基础介绍
  • SQL增查
  • Windows下odbc配置连接SQL Server
  • .Net将控制台的输出信息存入到日志文件按分钟生成日志文件
  • 【JavaEE进阶】使用云服务器搭建Linux环境
  • Java网络通信:UDP和TCP
  • 关于CDH以及HUE的介绍
  • vue-seo优化
  • Android构建流程与Transform任务
  • 题解:P13311 [GCJ 2012 Qualification] Speaking in Tongues
  • java面向对象-多态