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




