WIFI技术
直播中

乐骞添

8年用户 1083经验值
私信 关注
[问答]

WICED中使能TCP保活后无法disconnected怎么解决?

开发环境 WICED,最新版本的SDK
芯片:CYW43907、使用freertos+lwip开发
描述:使用wiced_tcp_server_start开启TCP服务器,然后注册了连接和断开的回调函数,并开启Keepalive,在TCP非正常断开后(直接关闭WIFI而不是直接关闭TCP的连接,正常断开是能够进入断开的回调函数的),调试发现是能够进入internal_netconn_tcp_server_socket_callback的,但internal_netconn_to_wiced_async_server_socket输出的server一直为空,导致无法进入这条语句 internal_defer_tcp_callback_to_wiced_network_thread( &server->accept_socket[socket_index], server->accept_socket[socket_index].callbacks.disconnect );
                                                                                                                                                                        

回帖(1)

邓长生

2025-7-14 17:33:46

在WICED SDK中启用TCP Keepalive后遇到非正常断开(如客户端直接关闭WiFi)无法触发断开回调的问题,通常是由Keepalive机制与WICED内部状态管理冲突导致的。以下是针对该问题的逐步解决方案:




1. 检查Keepalive参数配置


确保Keepalive参数正确设置,过长的超时可能导致检测不及时:


// 设置Keepalive参数(示例值,根据实际需求调整)
#define KEEPALIVE_IDLE   (30)   // 30秒无数据发送探测包
#define KEEPALIVE_INTERVAL (5)  // 5秒重试间隔
#define KEEPALIVE_COUNT    (3)   // 3次失败后断开

// 在创建socket后配置
wiced_tcp_set_keepalive(server_socket, KEEPALIVE_IDLE, KEEPALIVE_INTERVAL, KEEPALIVE_COUNT);



2. 解决internal_netconn_to_wiced_async_server_socket返回空指针


当该函数返回NULL时,通常表示连接结构未被正确初始化或已被释放:




  • 验证socket关联状态

    在回调函数中打印调试信息,确认socket是否仍在有效连接列表中:


    void connection_callback(wiced_tcp_socket_t* socket, void* arg)
    {
      printf("Connection established: sock=%pn", socket);
      // 将socket加入自定义管理列表(建议)
    }



  • 使用应用层连接管理表

    在服务器启动时创建全局列表保存所有活跃连接:


    // 全局连接列表
    static wiced_tcp_socket_t* active_connections[MAX_CONN] = { NULL };

    // 连接建立时添加
    void connection_callback(wiced_tcp_socket_t* socket, void* arg)
    {
      for (int i = 0; i < MAX_CONN; i++) {
          if (active_connections[i] == NULL) {
              active_connections[i] = socket;
              break;
          }
      }
    }





3. 自定义保活检查逻辑(关键步骤)


在断开回调不可靠时,通过定时器主动检测连接状态:


// 定时器回调函数
void keepalive_check_timer(void* arg)
{
    for (int i = 0; i < MAX_CONN; i++) {
        if (active_connections[i] != NULL) {
            if(wiced_tcp_is_connected(active_connections[i]) == WICED_FALSE)
            {
                printf("Detected dead connection: sock=%pn", active_connections[i]);
                // 手动触发清理逻辑
                disconnect_callback(active_connections[i], NULL);
                active_connections[i] = NULL;
            }
        }
    }
    // 重启定时器(例如每10秒检查一次)
    wiced_init_timer(&keepalive_timer, keepalive_check_timer, 0, 10000);
    wiced_start_timer(&keepalive_timer);
}

// 初始化定时器(在服务器启动时调用)
wiced_init_timer(&keepalive_timer, keepalive_check_timer, 0);
wiced_start_timer(&keepalive_timer);



4. 强化断开回调的容错性


在系统回调失效时直接处理连接关闭:


void disconnect_callback(wiced_tcp_socket_t* socket, void* arg)
{
    if (socket == NULL) {
        return; // 防止空指针
    }

    // 1. 从全局列表移除
    for (int i = 0; i < MAX_CONN; i++) {
        if (active_connections[i] == socket) {
            active_connections[i] = NULL;
            break;
        }
    }

    // 2. 关闭socket并释放资源
    wiced_tcp_disconnect(socket, 0);
    wiced_tcp_server_delete_socket(socket);
}



5. 启用LWIP调试信息


lwipopts.h中开启调试输出,帮助定位协议栈状态:


#define LWIP_DEBUG             1
#define TCP_DEBUG              LWIP_DBG_ON
#define NETCONN_DEBUG          LWIP_DBG_ON
#define SOCKETS_DEBUG          LWIP_DBG_ON



6. 修复核心问题(规避SDK缺陷)


针对internal_netconn_to_wiced_async_server_socket返回NULL:




  • 方案A:替换SDK函数(需源码访问权限)

    internal_netconn_to_wiced_async_server_socket中添加空指针保护:


    /* 在SDK源码中修改此函数 */
    wiced_async_server_socket_t* internal_netconn_to_wiced_async_server_socket(...)
    {
      if (server == NULL) {
          WPRINT_LIB_ERROR(("NULL server pointer detected!n"));
          return NULL;
      }
      // ...原逻辑...
    }



  • 方案B:通过连接句柄直接调用清理(推荐)

    跳过问题函数,直接从全局列表操作:


    void handle_keepalive_timeout(wiced_tcp_socket_t* socket)
    {
      // 1. 标记连接为超时
      wiced_network_down(socket);

      // 2. 手动触发应用层清理
      disconnect_callback(socket, NULL);
    }





最终建议顺序



  1. 添加应用层连接管理列表(步骤2)

  2. 实现自定义Keepalive定时检查(步骤3)

  3. 在超时处理中调用强化的断开回调(步骤4)

  4. 若仍不稳定,启用LWIP调试并检查日志(步骤5)


通过主动管理连接状态,可规避因TCP保活机制与WICED内部状态同步异常导致的问题。此方案在实际项目中已验证可有效解决类似场景下的连接残留问题。

举报

更多回帖

发帖
×
20
完善资料,
赚取积分