You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

Flutter连接ESP32 AP时出现WebSocketChannelException/HttpException:可Ping通但连接失败(Android端)

Flutter连接ESP32 AP时出现WebSocketChannelException/HttpException:可Ping通但连接失败(Android端)

从你的描述和报错信息来看,核心矛盾是ICMP(ping)能通但TCP连接(WebSocket/HTTP)失败,而且第三方WebSocket工具也连不上,这说明问题大概率不在Flutter/Android的基础配置(你已经做了大部分必要的设置),而是在ESP32的服务端实现或者网络协议/端口匹配上。下面分点帮你逐一排查:

1. 最可能的原因:ESP32端没有正确运行WebSocket服务

你提到ESP32用了server.listen(80),但如果这是普通的HTTP Server(比如Arduino的WebServer库),它是无法处理WebSocket连接的!WebSocket需要专门的握手协议,普通HTTP Server会因为协议不匹配直接关闭连接,导致你看到的"Connection closed before full header was received"错误。

解决方法:

确保ESP32使用支持WebSocket的库,比如Arduino生态的AsyncWebSocket + AsyncWebServer,示例代码如下:

#include <WiFi.h>
#include <AsyncWebSocket.h>
#include <AsyncWebServer.h>

const char* AP_SSID = "ESP32-AP";
const char* AP_PASS = "your-password";
AsyncWebServer server(80);
AsyncWebSocket ws("/ws"); // WebSocket的路径为/ws,需和Flutter端对应

// WebSocket事件处理回调
void onWsEvent(AsyncWebSocket* server, AsyncWebSocketClient* client, AwsEventType type, 
               void* arg, uint8_t* data, size_t len) {
  switch(type) {
    case WS_EVT_CONNECT:
      Serial.printf("客户端 [%u] 已连接,IP: %s\n", client->id(), client->remoteIP().toString().c_str());
      break;
    case WS_EVT_DISCONNECT:
      Serial.printf("客户端 [%u] 已断开\n", client->id());
      break;
    // 接收消息等其他逻辑可在这里扩展
  }
}

void setup() {
  Serial.begin(115200);
  // 启动ESP32 SoftAP
  WiFi.softAP(AP_SSID, AP_PASS);
  IPAddress apIP = WiFi.softAPIP();
  Serial.print("ESP32 AP IP: ");
  Serial.println(apIP); // 确认输出为192.168.1.1

  // 绑定WebSocket事件并启动服务
  ws.onEvent(onWsEvent);
  server.addHandler(&ws);
  server.begin();
}

void loop() {
  ws.cleanupClients(); // 定期清理无效连接
  delay(10);
}

对应的Flutter代码里,WebSocket URI要改成带路径的版本:

final uri = Uri.parse("ws://192.168.1.1/ws"); // 路径/ws必须和ESP32配置对应
channel = WebSocketChannel.connect(uri);
channel!.stream.listen((event) => print(event), onError: (e) => print(e));

2. 奇怪的端口0报错:检查Flutter代码的URI是否被意外修改

你的错误日志里出现了uri = http://192.168.1.1:0,这明显异常——端口0是无效的。请仔细检查你的代码:

  • 有没有其他逻辑意外覆盖了URI的端口?比如使用了未初始化的变量作为端口?
  • 有没有拼写错误?比如把80写成了0
  • 可以在Uri.parse后打印URI确认:print(uri);,确保输出是ws://192.168.1.1/ws(或你配置的对应路径)。

3. 网络层面排查:确认TCP端口是否可达

既然ping能通,说明IP层连通,但TCP端口可能没在监听。可以用Android的ADB Shell测试:

  1. 连接电脑,打开终端执行adb shell
  2. 输入telnet 192.168.1.1 80
    • 如果提示Connection refused:说明ESP32的80端口没有服务在监听,回到第一步检查ESP32的服务代码
    • 如果能连接(进入空白界面):说明端口可达,此时可以手动发送WebSocket握手请求测试协议是否匹配:
      输入以下内容(注意换行要正确,最后空一行):
      GET /ws HTTP/1.1
      Host: 192.168.1.1
      Upgrade: websocket
      Connection: Upgrade
      Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
      Sec-WebSocket-Version: 13
      
      如果ESP32是正确的WebSocket服务,会返回HTTP/1.1 101 Switching Protocols的响应;否则会返回HTTP错误,说明服务端协议不匹配。

4. 其他可能的小问题

  • ESP32 AP的DHCP/IP冲突:检查Android设备的WiFi详情,确认IP地址在192.168.1.x网段(和ESP32的静态IP同网段)
  • ESP32的连接数限制:ESP32的SoftAP默认最大连接数是4,确保没有超过
  • Android网络缓存:重启Android设备和ESP32,清除WiFi缓存后重新连接

最后再核对你的Android配置(确保没有遗漏)

确认AndroidManifest.xml的配置完全正确:

<manifest ...>
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

    <application
        ...
        android:usesCleartextTraffic="true"
        android:networkSecurityConfig="@xml/network_security_config">
        ...
    </application>
</manifest>

res/xml/network_security_config.xml内容:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <domain-config cleartextTrafficPermitted="true">
        <domain includeSubdomains="true">192.168.1.1</domain>
    </domain-config>
</network-security-config>

备注:内容来源于stack exchange,提问作者Encuesta Satisfaccion

火山引擎 最新活动