Android 14下TCP/IP连接失败问题求助(附代码与堆栈信息)
Android 14下TCP Socket连接超时的代码级解决方案
问题描述
设备升级至Android 14后,自研APP使用以下代码创建TCP Socket连接时出现SocketTimeoutException:
Socket s = new Socket(); InetSocketAddress endpoint = new InetSocketAddress("192.168.137.1", 50024); s.connect(endpoint, 3000);
对应的错误堆栈:
java.net.SocketTimeoutException: failed to connect to /192.168.137.1 (port 50024) from /172.27.250.17 (port 42916) after 3000ms at libcore.io.IoBridge.connectErrno(IoBridge.java:235) at libcore.io.IoBridge.connect(IoBridge.java:179) at java.net.PlainSocketImpl.socketConnect(PlainSocketImpl.java:142) at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:390) at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:230) at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:212) at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:436) at java.net.Socket.connect(Socket.java:646)
手动重置WiFi可临时规避问题,需代码层面的永久解决方案。
问题分析
从堆栈信息可见,APP尝试从172.27.250.17(非目标WiFi网段)连接目标192.168.137.1,说明Android 14的网络路由逻辑可能优先选择了非预期的网络接口(如移动数据、其他WiFi)。重置WiFi会让系统重新选择正确的网卡,但需通过代码强制绑定Socket到目标WiFi的网络接口。
代码解决方案
1. 权限声明
在AndroidManifest.xml中添加必要权限:
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <!-- Android 10+ 获取WiFi信息需定位权限 -->
2. 动态申请权限(Android 6+)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { String[] requiredPermissions = { Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.CHANGE_NETWORK_STATE }; boolean needRequest = false; for (String perm : requiredPermissions) { if (checkSelfPermission(perm) != PackageManager.PERMISSION_GRANTED) { needRequest = true; break; } } if (needRequest) { requestPermissions(requiredPermissions, 1001); } }
3. 绑定Socket到目标WiFi网络
通过ConnectivityManager获取目标WiFi对应的Network对象,将Socket绑定到该网络后再发起连接:
// 获取系统服务 ConnectivityManager connManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE); Network targetNetwork = null; // 方式1:获取当前已连接的WiFi网络 NetworkInfo activeNetworkInfo = connManager.getActiveNetworkInfo(); if (activeNetworkInfo != null && activeNetworkInfo.getType() == ConnectivityManager.TYPE_WIFI && activeNetworkInfo.isConnected()) { targetNetwork = connManager.getActiveNetwork(); } // 方式2:根据SSID指定特定WiFi(如果需要连接固定SSID) if (targetNetwork == null && wifiManager != null) { List<Network> allNetworks = connManager.getAllNetworks(); String targetSsid = "\"你的目标WiFi名称\""; // 注意SSID返回值带双引号 WifiInfo currentWifiInfo = wifiManager.getConnectionInfo(); if (currentWifiInfo != null && targetSsid.equals(currentWifiInfo.getSSID())) { // 当前已连接目标WiFi,直接获取对应Network targetNetwork = connManager.getActiveNetwork(); } else { // 遍历所有网络查找目标WiFi for (Network network : allNetworks) { NetworkInfo networkInfo = connManager.getNetworkInfo(network); if (networkInfo != null && networkInfo.getType() == ConnectivityManager.TYPE_WIFI && networkInfo.isConnected()) { targetNetwork = network; break; } } } } // 绑定Socket并发起连接 if (targetNetwork != null) { Socket socket = new Socket(); try { // Android 6+支持绑定Network到Socket if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { targetNetwork.bindSocket(socket); } InetSocketAddress endpoint = new InetSocketAddress("192.168.137.1", 50024); socket.connect(endpoint, 3000); // 连接成功后的业务逻辑处理 } catch (SocketTimeoutException e) { // 超时处理 e.printStackTrace(); } catch (IOException e) { // 其他IO异常处理 e.printStackTrace(); } finally { // 记得关闭Socket try { socket.close(); } catch (IOException e) { e.printStackTrace(); } } } else { // 未找到目标WiFi网络,提示用户连接 Toast.makeText(this, "请连接目标WiFi网络", Toast.LENGTH_SHORT).show(); }
原理说明
通过Network.bindSocket()方法,强制Socket使用指定的WiFi网络接口进行通信,避免Android 14系统在多网络环境下自动选择非预期路由的问题,从根源上解决连接超时问题,无需手动重置WiFi。
内容的提问来源于stack exchange,提问作者たなかたろう
相关产品推荐
相关产品推荐

