RT-Thread论坛
直播中

李巍

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

at-client连接和发送会超时,什么原因导致的?


  • 我是用paho-mqtt进行通信,底层用at-client组件进行tcp ,有时会出现send以后等不到确认信号,但是超时以后立马又收到确认信号了。
操作:


  • 1:发送 AT+QISEND=1,2;等待完成的信号。


    • 再urc回调里面,如果收到AT+QISEND=1,2 表示发送成功,发送完成信号。
  • 3.操作1继续往下执行。
现象:

现在总是出现超时,然后打印收到了回复;一开始我以为超时太短了,但是延长到60s也还是这个现象。
情况1:

我确认这两个个地方不是同一个线程,我是另外的线程调用的send, urc在回调线程。
情况2:

发生的频率不高,但是总会发生几次


回帖(1)

王强

2025-10-20 17:05:46

根据你的描述,使用 paho-mqtt + at-client 组件时出现发送超时后又立即收到确认信号的问题,可能由以下原因导致:




根本原因分析




  1. AT 指令处理流程的线程竞争  



    • 虽然发送线程和 URC 回调线程独立,但 at-client 内部可能存在资源锁竞争。当发送线程阻塞等待响应时,URC 线程可能因锁争用被延迟执行,导致超时后回调才被处理。

    • 典型场景:发送线程持有锁执行 AT+QISEND → URC 回调需获取同一锁处理响应 → 发送线程未释放锁时 URC 被阻塞 → 触发超时 → 发送线程释放锁 → URC 立即执行。




  2. URC 响应延迟到达  



    • 模块(如蜂窝模组)处理数据发送时,底层网络波动可能导致响应延迟:

      • TCP 层重传机制(如网络闪断)使 ACK 延迟到达。

      • 模组内部队列拥塞(如高负载时),响应 +QISEND URC 被堆积。





  3. 串口数据接收瓶颈  



    • 硬件缓冲限制:串口 RX 缓冲区较小,高负载时数据可能被覆盖。

    • 软件解析延迟at-client 解析大量 URC 数据(如网络状态通知)时,业务 URC 被延迟处理。




  4. 超时机制与事件触发顺序错位  



    • 超时判断和 URC 回调可能发生在 极短的时间窗口内:  
      timeline
      title 超时与响应时序冲突
      section 时间线
      发送线程 : 0ms : 发送指令
                   5000ms : 判定超时
      URC线程  : 5001ms : 收到响应并回调

      尽管实际响应在超时后 1ms 到达,但业务层已进入超时处理逻辑。







解决方案


1. 优化线程同步机制



  • 检查锁粒度:确保 at-client 内部锁范围最小化,避免发送/回调线程互斥。


  • 无锁队列传递事件:将 URC 事件存入无锁队列,由独立线程处理,避免阻塞:


     // 伪代码:URC 回调仅入队
    void urc_callback(char *resp) {
         ringbuf_push(resp); // 无锁操作
    }

    // 独立线程处理队列
    void urc_process_thread() {
         while (1) {
             char *resp = ringbuf_pop();
             handle_response(resp); // 实际业务处理
         }
    }



2. 调整超时与重试策略



  • 动态超时时间:根据网络质量动态调整超时(如初始 5s,失败后指数退避)。

  • 二次确认机制:超时后不立即报错,短暂等待(如 100ms)再检查 URC 是否到达。
     int send_with_retry() {
         send_at_command();
         if (wait_semaphore(5000) == TIMEOUT) {
             sleep_ms(100);       // 关键:延迟等待可能的滞后响应
             if (check_urc_arrived()) {
                 return SUCCESS;   // 实际未超时
             }
             return RETRY;        // 真正超时
         }
         return SUCCESS;
    }


3. 底层通信优化



  • 扩大串口缓冲区:确保硬件 FIFO 和驱动层缓冲区足够大。

  • 提升 URC 优先级:调整 URC 任务线程优先级至最高(如 RTOS 中高于发送线程)。

  • 过滤无关 URC:关闭非必要 URC(如 +CREG),减少解析负担:
     AT+QURC="recv",0  // 关闭非核心 URC


4. 模块固件与网络检查



  • 更新模组固件:修复已知的响应延迟 Bug(常见于 Quectel/移远模组)。

  • 网络心跳保活:添加 TCP Keep-Alive 避免中间链路断开:
     AT+QISOCKOPT=1,1,300  // 每 300 秒 Keep-Alive




验证步骤




  1. 日志追踪

    在发送线程和 URC 回调中添加精确时间戳日志(微秒级):


    [TX] Send AT+QISEND: T=12345678 μs
    [URC] Recv +QISEND: T=12355679 μs  // 实际延迟 10ms,但超时设定为 5s

    确认是 响应真延迟 还是 处理被阻塞




  2. 压力测试复现:  



    • 在高频发送场景下(如 50 条/秒)测试,观察是否更容易触发。

    • 若触发率上升,指向资源竞争或队列拥塞。




  3. 模拟网络延迟

    在串口链路中注入人工延迟(如 RS232 延时器),验证超时逻辑容错性。






总结


根本症结在于 “响应到达时机”“超时判定窗口” 的临界竞争,结合底层阻塞导致。优先排查:



  • at-client 内部的线程/锁模型  

  • ✅ 串口数据路径是否有瓶颈  

  • ✅ 注入短暂延迟等待再判定超时  


通过上述策略综合优化,可显著降低偶发超时概率。

举报

更多回帖

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