Flutter安卓连接IoT设备WiFi重登触发SocketException errno=64问题
问题现象
使用有效账号凭证操作登录时,会触发登录失败,抛出如下异常:
[ERROR:flutter/lib/ui/ui_dart_state.cc(198)] Unhandled Exception: SocketException: Connection failed (OS Error: Machine is not on the network, errno = 64), address = login.parker.com, port = 443 E/flutter ( 5780): #0 _NativeSocket.startConnect (dart:io-patch/socket_patch.dart:682:35) E/flutter ( 5780): #1 _RawSocket.startConnect (dart:io-patch/socket_patch.dart:1817:26) E/flutter ( 5780): #2 RawSocket.startConnect (dart:io-patch/socket_patch.dart:27:23) E/flutter ( 5780): #3 RawSecureSocket.startConnect (dart:io/secure_socket.dart:299:22) E/flutter ( 5780): #4 SecureSocket.startConnect (dart:io/secure_socket.dart:77:28) E/flutter ( 5780): #5 _ConnectionTarget.connect (dart:_http/http_impl.dart:2449:26) E/flutter ( 5780): #6 _HttpClient._getConnection.connect (dart:_http/http_impl.dart:2867:12) E/flutter ( 5780): #7 _HttpClient._getConnection (dart:_http/http_impl.dart:2872:12) E/flutter ( 5780): #8 _HttpClient._openUrl (dart:_http/http_impl.dart:2727:12) E/flutter ( 5780): #9 _HttpClient.openUrl (dart:_http/http_impl.dart:2591:7) E/flutter ( 5780): #10 IOClient.send (package:http/src/io_client.dart:35:38) E/flutter ( 5780): #11 BaseClient._sendUnstreamed (package:http/src/base_client.dart:93:38) E/flutter ( 5780): #12 BaseClient.post (package:http/src/base_client.dart:32:7) E/flutter ( 5780): #13 post.<anonymous closure> (package:http/http.dart:69:16) E/flutter ( 5780): #14 _withClient (package:http/http.dart:164:20) E/flutter ( 5780): #15 post (package:http/http.dart:68:5)
复现规律
- 仅在App通过WiFi连接IoT设备的场景下触发
- 触发路径:App通过SSH连接从IoT设备拉取信息后,用户点击退出登录再重新登录时,必然抛出上述异常
- 报错特征:系统返回OS错误
errno = 64,即设备不在网络中,无法连通公网登录地址login.parker.com的443端口 - 临时恢复方案:强制杀掉App进程后重新打开,登录功能即可恢复正常
关联代码
SSH连接实现代码如下:
client = SSHClient( host: '192.168.0.1', port: 22, username: _username, passwordOrKey: _password, );
根因分析
报错errno = 64对应系统错误码ENETUNREACH,即网络不可达,核心原因是 App的公网请求被错误路由到了无公网出口的IoT局域网上:
- IoT设备释放的WiFi热点本身不具备公网访问能力,安卓/iOS系统默认不会将这类无公网的WiFi设为全局默认路由,但部分Flutter SSH客户端库在建立局域网SSH连接时,会主动将当前进程的所有Socket请求绑定到该IoT WiFi网络上,操作完成后不会自动解绑。
- 后续用户触发登录请求时,Flutter内置的HttpClient、第三方http包默认复用进程级的网络路由配置,所有请求都发往无公网能力的IoT局域网,自然无法连接公网登录域名,抛出网络不可达错误。
- 强制杀进程会清空进程级的网络绑定状态,重启后App恢复使用系统默认路由,因此登录功能恢复正常。
解决方案
- 每次SSH交互完成后必须主动清理连接:和IoT设备的通信结束后,第一时间调用
client.close()断开SSH连接,不要在后台保留SSH长连接。如果使用的SSH库提供了自动网络绑定的配置项,直接关闭该能力。 - 退出登录时重置HTTP客户端:触发退出登录逻辑时,主动销毁当前持有的http客户端实例、清空连接池缓存,后续登录请求使用全新的客户端实例发起,避免复用旧连接绑定的错误路由。
- 增加公网请求的路由校验:发起登录请求前,先校验当前默认网络的公网连通性,如果检测到当前默认网络是无公网能力的局域网,主动重置网络绑定,将公网请求路由到具备公网访问能力的网络(如移动数据、正常办公/家庭WiFi)上。
- 针对IoT场景做网络适配:连接IoT设备WiFi时,不要让局域网SSH请求修改全局网络路由,局域网请求单独绑定IoT网络,公网请求走系统默认公网路由,两类请求的网络配置互相隔离。
内容的提问来源于stack exchange,提问作者user3571936
相关产品推荐
相关产品推荐

