You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于LWIP Netconn API的TCP连接优雅关闭与重连问题排查

FreeRTOS v10.0.0 + LwIP 2.1.2 Netconn API TCP优雅关闭与重连问题解决

问题原因分析

  • 当Linux端Netcat关闭时,TCP连接已被动断开,此时调用netconn_close()返回ERR_CONN(连接不存在)属于正常现象。
  • netconn_delete()返回ERR_INPROGRESS是因为LwIP内部仍有未完成的TCP协议栈操作(如连接处于FIN_WAIT状态),无法立即释放资源。
  • 重连时netconn_bind()返回ERR_USE,核心原因是原监听用的tcpListenNetconn未被正确释放,端口一直被占用;其次是TCP端口关闭后可能处于TIME_WAIT状态,默认无法立即复用。

解决方案

1. 修正连接异常处理流程

  • 先判断错误类型,避免对已断开的连接调用netconn_close()。
  • 处理netconn_delete()的ERR_INPROGRESS错误,通过循环等待确保资源释放完成。
  • 必须释放监听用的netconn资源,避免端口占用。

2. 实现TCP优雅关闭

  • 主动关闭时,先调用netconn_shutdown()关闭读写通道,再执行关闭和删除操作;被动关闭时直接处理资源释放。

3. 解决端口占用问题

在lwipopts.h中开启TCP端口复用配置:

#define TCP_REUSE 1  // 允许复用处于TIME_WAIT状态的端口
#define TCP_TIMEWAIT_MSL 2000  // 缩短TIME_WAIT时长(单位:ms,按需调整)

修改后的代码示例

void FooMethod()
{
    netconn* tcpListenNetconn = NULL;
    netconn* connection = NULL;
    err_t err;

    // 创建监听Netconn
    tcpListenNetconn = netconn_new(NETCONN_TCP);
    if (tcpListenNetconn == NULL) {
        return;
    }

    // 绑定端口(开启复用后无需担心TIME_WAIT)
    err = netconn_bind(tcpListenNetconn, IP4_ADDR_ANY, TCP_PORT);
    if (err != ERR_OK) {
        netconn_delete(tcpListenNetconn);
        return;
    }

    // 开始监听
    netconn_listen(tcpListenNetconn);

    // 等待客户端连接
    err = netconn_accept(tcpListenNetconn, &connection);
    if (err != ERR_OK || connection == NULL) {
        netconn_delete(tcpListenNetconn);
        return;
    }

    uint8_t buffer = 0x65;
    while (1) {
        err = netconn_write(connection, &buffer, 1, NETCONN_COPY);
        if (err != ERR_OK) {
            break;
        }
        // 避免高频发送,添加适当延时
        vTaskDelay(pdMS_TO_TICKS(100));
    }

    // 处理连接资源释放
    if (connection != NULL) {
        // 判断连接状态,避免已断开时调用close出错
        if (netconn_get_state(connection) != NETCONN_NONE) {
            // 主动关闭读写通道
            netconn_shutdown(connection, SHUT_RDWR);
            // 尝试关闭连接,处理操作中状态
            err = netconn_close(connection);
            if (err == ERR_INPROGRESS) {
                do {
                    vTaskDelay(pdMS_TO_TICKS(100));
                    err = netconn_close(connection);
                } while (err == ERR_INPROGRESS);
            }
        }
        // 循环等待删除完成
        do {
            err = netconn_delete(connection);
            if (err == ERR_INPROGRESS) {
                vTaskDelay(pdMS_TO_TICKS(100));
            }
        } while (err == ERR_INPROGRESS);
        connection = NULL;
    }

    // 释放监听Netconn
    if (tcpListenNetconn != NULL) {
        netconn_delete(tcpListenNetconn);
        tcpListenNetconn = NULL;
    }
}

// 重连任务:循环调用连接逻辑,添加重连间隔
void ReconnectTask(void* arg)
{
    while (1) {
        FooMethod();
        // 避免频繁重连,添加间隔
        vTaskDelay(pdMS_TO_TICKS(2000));
    }
}

关键注意事项

  • 必须确保所有netconn资源都被正确释放,包括监听和连接用的实例,否则会导致内存泄漏和端口占用。
  • 不要忽略netconn_new()、netconn_bind()等操作的错误返回值,添加必要的错误处理。
  • 端口复用配置TCP_REUSE需根据实际场景调整,过度缩短TIME_WAIT可能影响TCP连接稳定性。

内容的提问来源于stack exchange,提问作者user3143155

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 17:19:03