Android 7.1.2设备同时使用以太网与WiFi通信的实现方案求助
Android 7.1.2 WiFi与以太网双网并行实现方案
问题根因
Android 7.1.2默认仅会为优先级最高的网络配置全局默认路由,并非系统层面禁止双网卡同时收发数据。当前代码无法实现双网并行的核心原因有两点:
- 以太网绑定逻辑无效:网络回调中单独创建的Socket与ModbusClient内部使用的连接完全独立,绑定操作不会作用于实际的Modbus请求
- 网络路由未做分流:若直接全局绑定进程到某一网卡,所有流量都会走该网卡,另一网卡的请求自然无法正常发送
前置权限配置
先在项目的AndroidManifest.xml中声明所需权限,以下权限不需要动态申请,清单文件中声明即可生效:
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
分步实现指引
1. 实现以太网状态监听
首先声明全局变量存储以太网的Network实例,注册系统网络回调实时获取以太网连接状态,不要在回调中创建无意义的独立Socket:
// 全局变量存储以太网网络实例 private Network mEthernetNetwork = null; private final ConnectivityManager.NetworkCallback ethernetCallback = new ConnectivityManager.NetworkCallback() { @Override public void onAvailable(Network network) { super.onAvailable(network); mEthernetNetwork = network; } @Override public void onLost(Network network) { super.onLost(network); mEthernetNetwork = null; } }; // 在页面onCreate中注册监听 ConnectivityManager connectivityManager = (ConnectivityManager) getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE); NetworkRequest ethernetRequest = new NetworkRequest.Builder() .addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET) .build(); connectivityManager.requestNetwork(ethernetRequest, ethernetCallback, new Handler(Looper.getMainLooper())); // 不要忘记在页面onDestroy中注销回调 @Override protected void onDestroy() { super.onDestroy(); connectivityManager.unregisterNetworkCallback(ethernetCallback); }
2. 改造Modbus请求逻辑,实现网络分流
新手优先选择临时进程绑定方案,不需要修改Modbus依赖库源码,改造成本最低:
在Modbus请求的工作线程中,连接控制器前临时将进程绑定到以太网,请求结束后无论成功失败,都切回原默认网络(WiFi),保证访问远端服务器的流量正常走WiFi。改造后的doInBackground逻辑如下:
@Override protected String doInBackground(String... params) { ConnectivityManager cm = (ConnectivityManager) MyApp.getInstance().getSystemService(Context.CONNECTIVITY_SERVICE); // 先保存当前默认网络(即WiFi网络) Network defaultNetwork = cm.getActiveNetwork(); try { if (mEthernetNetwork != null) { // 绑定当前进程所有流量到以太网 cm.bindProcessToNetwork(mEthernetNetwork); } mClientReadAll.Connect(); // 原有寄存器读取逻辑无需修改 int[] registerBlock = mClientReadAll.ReadHoldingRegisters(Constants.RegisterRead.HR_MODE.getRegister()- 1, 16); int[] wideRegisters = new int[] { Modbus.convertWideRegister(mClientReadAll.ReadHoldingRegisters(Constants.RegisterRead.HR_ACTUAL_POSITION.getRegister() - 1, 2)), Modbus.convertWideRegister(mClientReadAll.ReadHoldingRegisters(Constants.RegisterRead.HR_TARGET_POSITION.getRegister() - 1, 2)), Modbus.convertWideRegister(mClientReadAll.ReadHoldingRegisters(Constants.RegisterRead.HR_ROM_DELTA.getRegister() - 1, 2)), Modbus.convertWideRegister(mClientReadAll.ReadHoldingRegisters(Constants.RegisterRead.HR_REWIND_ZERO.getRegister() - 1, 2)) }; int[] tensionRegister = mClientReadAll.ReadHoldingRegisters(Constants.RegisterRead.HR_ACTUAL_TENSION.getRegister() - 1, 1); Modbus.updateAllRegisters(registerBlock, wideRegisters, tensionRegister); } catch (Exception e) { Log.i(TAG, "Modbus读寄存器异常: " + e.getMessage()); e.printStackTrace(); } finally { try { mClientReadAll.Disconnect(); } catch (Exception e) { Log.i(TAG, "Modbus断开连接异常"); } // 必须在finally块中切回原默认网络,避免其他请求被路由到以太网 cm.bindProcessToNetwork(defaultNetwork); } return null; }
bindProcessToNetwork是Android 6.0及以上版本开放的官方公开API,7.1.2系统完全支持,不需要root权限,也不需要修改系统源码,是应用层实现双网分流最稳定的方案。
3. 进阶优化方案(稳定性更高)
如果使用的Modbus开源库支持自定义SocketFactory,可以直接传入mEthernetNetwork.getSocketFactory()创建Modbus连接,这样Modbus流量从Socket创建阶段就固定走以太网,不需要反复绑定/解绑进程网络,完全不会干扰WiFi请求的正常路由,适合长期稳定运行的场景。如果当前使用的Modbus库不支持自定义SocketFactory,替换为j2mod等主流开源Modbus库即可。
注意事项
- 提前在平板系统设置中为以太网配置静态IP,确保以太网和WiFi处于不同网段,例如WiFi网段为
192.168.1.x时,以太网可配置为192.168.2.x,避免路由冲突 - 网络切回操作必须放在
finally块中执行,防止Modbus请求抛出异常时,进程持续绑定在以太网上导致服务器请求失败 - 不要在
onAvailable回调中全局绑定进程到以太网后不做切回,否则所有App流量都会走以太网,WiFi请求将无法正常发送 - 测试阶段可先将Modbus轮询间隔调整为500ms,验证双网通信稳定后再根据需求调整轮询频率
内容的提问来源于stack exchange,提问作者Jake
相关产品推荐
相关产品推荐

