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

NodeMCU(ESP8266)定时WiFi发送数据时TCP连接复位问题求助

问题分析与解决方案

先来说说你遇到的两个核心问题,一步步给你拆解清楚:

一、为什么Ticker回调里无法获取有效WiFiClient?

你猜的方向有道理,但本质原因更关键:ESP8266的Ticker回调是运行在中断上下文里的,而WiFi相关的API(包括server.available())绝对不能在中断中调用。

ESP8266的WiFi栈依赖FreeRTOS的任务调度、信号量等底层机制,中断上下文里没有这些运行环境,强行调用WiFi API会导致资源锁死、数据混乱,甚至直接触发系统崩溃。这就是为什么你的串口只打印40ms_Data A——server.available()在中断里根本无法正常工作,永远拿不到有效的客户端对象。

你后来改用Ticker设置标志位、在loop()里处理WiFi连接的思路是完全正确的,这才是符合ESP8266运行机制的正确做法。

二、为什么发送几条数据后TCP连接被复位?

你现在的代码能运行,但出现TCP复位,主要有这几个潜在原因:

1. 未处理客户端输入,导致缓冲区溢出

TCP连接是双向的,你的笔记本作为客户端,可能会发送数据(比如HTTP请求的头部信息),如果你的代码一直不读取这些数据,客户端的发送缓冲区会被填满,最终客户端会主动断开连接,或者ESP的WiFi栈因为接收缓冲区溢出而发送RST包。

2. delay(1)仍会抢占WiFi栈的后台处理时间

虽然你加了delay(1),但loop()里的while(client.connected())循环还是会持续占用CPU。ESP8266的WiFi栈需要定期处理TCP的ACK确认、心跳包等后台任务,如果CPU被长时间占用,WiFi栈无法及时处理这些事务,就会被判定为连接超时,触发复位。

3. 缺少连接超时处理逻辑

你定义了CLIENT_TIMEOUT但没实际使用,当客户端长时间没有数据交互时,ESP的WiFi栈可能会自动判定连接失效,主动发送RST包断开连接。

修复方案

给你修改后的代码,针对性解决这些问题:

#include <ESP8266WiFi.h>
#include <Ticker.h>

/* Put your SSID & Password */
const char* ssid = "NodeMCU";
const char* password = "12345678";

/* Put IP Address details */
IPAddress local_ip(192,168,1,1);
IPAddress gateway(192,168,1,1);
IPAddress subnet(255,255,255,0);

WiFiServer server(80);
const unsigned long CLIENT_TIMEOUT = 5000; // 5秒连接超时
Ticker Data_Rec;
bool Sending_40ms_Start_Flag = false;

void setup() {
  Serial.begin(115200);
  pinMode(D0, OUTPUT);
  
  WiFi.softAP(ssid, password);
  WiFi.softAPConfig(local_ip, gateway, subnet);
  delay(100);
  
  server.begin();
  Serial.println("HTTP server started");
  Data_Rec.attach_ms(500, flag_enable); // 测试用500ms触发
}

void flag_enable(){
  // 这里读取FPGA数据的逻辑
  // ...
  Sending_40ms_Start_Flag = true;
}

void loop(){
  WiFiClient client = server.available();
  if (client) {
    Serial.println("New client connected");
    unsigned long lastActivity = millis(); // 记录客户端最后活动时间
    
    while(client.connected()){
      // 先处理客户端发来的数据,避免缓冲区溢出
      while(client.available()){
        char c = client.read(); // 读掉所有输入数据
        // 如果需要处理客户端命令,可以在这里添加逻辑
      }
      
      // 检查超时:超过5秒无活动则断开连接
      if(millis() - lastActivity > CLIENT_TIMEOUT){
        Serial.println("Client timeout, disconnecting");
        break;
      }
      
      // 定时发送数据
      if (Sending_40ms_Start_Flag){
        client.println("Server listening.\r");
        Sending_40ms_Start_Flag = false;
        lastActivity = millis(); // 更新最后活动时间,避免误判超时
      }
      
      // 主动让出CPU,给WiFi栈处理后台任务(替代delay,非阻塞)
      yield();
    }
    
    // 主动断开客户端连接
    client.stop();
    Serial.println("Client disconnected");
  }
}

关键修改点说明:

  • 读取客户端输入:添加while(client.available())循环,把客户端发来的数据全部读掉,彻底避免缓冲区溢出问题。
  • 非阻塞超时处理:用millis()代替delay(),记录最后活动时间,超时后主动断开连接,避免系统自动复位。
  • 使用yield():代替delay(1),主动让出CPU给WiFi栈处理后台任务,确保TCP连接的ACK、心跳包等事务能及时处理。
  • 更新活动时间:每次发送数据后更新lastActivity,避免系统误判连接超时。

这样修改后,TCP连接应该能稳定保持,不会再出现频繁复位的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 08:12:53