在应用程序中使用多个网络接口

时间:2016-06-09 01:32:13

标签: android network-programming

我写了一个应用程序,通过wifi触发Sony qx智能手机可连接相机。但是,我需要通过另一个本地网络实时传输图像。由于wifi卡用于qx连接,我需要能够在usb上使用以太网从手机上传输图像。 Http请求将用于触发摄像头并从手机发送图像。

是否可以在具有两个网络接口设置的手机上的一个Android应用程序中指定某些http请求使用一个网络接口而其他人使用另一个网络接口?这是否需要通过路由表来完成,而不是java?

我正在使用的手机是一个根深蒂固的连线6p。

更新

目前,我能够使用以太网适配器(Nexus 6P)。设备通过以太网连接到本地网络。当Wi-Fi接口关闭时,我可以ping设备通过以太网连接的本地网络上的所有设备。但是,我无法访问该网络上任何设备(我知道它们正在运行)的Web服务器(不使用DNS),即通过浏览器应用程序进行Http。 nexus 6p通过Ubiquiti Station通过以太网连接到网络。这似乎是一个路由问题。

我可以在一个应用程序中连接(usb接口)并使用Wi-Fi,这让我相信可以使用以太网和Wi-Fi。

UPDATE2

经过更多测试后,似乎是权限问题。因为当我ping网络时,设备连接到以太网而没有先在终端中运行su,网络不存在。但是,当我运行su然后ping,我可以ping网络。因此,在访问以太网之前,我的应用似乎需要获得超级用户权限。我已经授予它超级用户访问权限,但没有任何改变。我读到,仅仅运行supost中的其中一条评论相比还不够。这是因为su只会产生一个死亡的root shell。这也解释了为什么我无法通过浏览器应用程序访问此网络上的任何Web服务器。是否有可能在进行HTTP调用时授予我的应用程序访问以太网接口,如授予HttpURLConnection root访问权限,如果这有意义(运行su不起作用)?似乎肯定有一个解决方案,因为HttpURLConnection可以通过USB网络共享接口(Nexus 6P称之为rndis0)进行调用。

更新3

我发现在线here,我可以将我的应用设为系统应用(认为这可能会授予应用eth0访问权限)。我刚将我的应用移至/system/app,然后重新启动。但是,这似乎不再给予应用程序特权(因此无法解决问题),或者制作应用程序系统还需要其他东西,而不仅仅是将其复制到/system/app

更新4

所以我能够在没有root权限的情况下让每个应用程序都能运行以太网!它似乎只适用于DHCP,并且不喜欢我正在使用的静态连接。它适用于启用Wi-Fi,但是,启用以太网时,我无法联系Wi-Fi网络上的任何设备。有没有解决的办法?是否与设置两个默认网关有关?

4 个答案:

答案 0 :(得分:3)

由于您使用的是Nexus 6P编程,因此您可以尝试使用ConnectivityManager中添加的新API来选择以太网作为您的流程的首选网络连接。

由于我不能像你那样建立类似的环境,我不确定它是否有效。这只是一个建议的解决方案,完全没有经过测试和验证。

ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);
Network etherNetwork = null;
for (Network network : connectivityManager.getAllNetworks()) {
    NetworkInfo networkInfo = connectivityManager.getNetworkInfo(network);
    if (networkInfo.getType() == ConnectivityManager.TYPE_ETHERNET) {
        etherNetwork = network;
    }
}
Network boundNetwork = connectivityManager.getBoundNetworkForProcess();
if (boundNetwork != null) {
    NetworkInfo boundNetworkInfo = connectivityManager.getNetworkInfo(boundNetwork);
    if (boundNetworkInfo.getType() != ConnectivityManager.TYPE_ETHERNET) {
        if (etherNetwork != null) {
            connectivityManager.bindProcessToNetwork(etherNetwork);
        }
    }
}

答案 1 :(得分:0)

大多数Android电视盒可以一起使用wifi和以太网。在我的设备中,我可以从这条路径启用以太网--- 设置 - >更多...>以太网--- 但是你的设备根本不会有像我这样的菜单。所以你应该做一个应用程序来做到这一点。此应用程序需要访问某些特定于系统的资源,因此您的设备需要植根或应用程序需要使用系统签名进行签名。 此主题也可以帮助您link

答案 2 :(得分:0)

就这最终如何解决而言,给予更多解释。

利用@ alijandro的答案,我能够在一个应用程序中在以太网和Wi-Fi之间来回切换。由于某些原因以太网工作,它需要网络网关提供DHCP地址,而不是静态。然后,因为@ alijandro的答案中使用的bindProcessToNetwork是每个进程,我决定将与QX相机的通信拆分为在单独的进程中运行的Service。主应用程序(另一个进程)将通过以太网将映像发布到本地网络。我成功地通过以太网HTTP连接本地网络上的设备,同时通过Wi-Fi触发QX。目前,我使用Messenger使用IPC进行通信,告诉QX触发Service要调用的方法。

答案 3 :(得分:0)

有一种简单的方法可以回答 OP 的原始问题,即如何使用 ConnectivityManager.requestNetwork() 在单个应用程序(而不是两个单独的应用程序进程)中执行此操作。

ConnectivityManager.requestNetwork() 的文档暗示了这一点:

<块引用>

... 例如,一个应用程序可以使用这个方法来获取一个 即使设备当前有数据,连接的蜂窝网络 通过以太网连接。这可能会导致蜂窝无线电消耗 额外的权力。或者,应用程序可以通知系统它 想要一个支持发送彩信的网络并让系统允许它 通过以下方式了解当前最好的 MMS 支持网络 提供网络回调。 ...

对于 OP 将 Wi-Fi 用于某些流量而以太网用于其他流量的场景,只需使用两个单独的请求调用 ConnectivityManager.requestNetwork() 两次。一种用于 TRANSPORT_WIFI,一种用于 TRANSPORT_ETHERNET。这里的关键是我们需要一种方法来唯一地识别这些网络。对于 OP 的场景,我们可以使用传输类型。

final NetworkRequest requestForWifi =
  new NetworkRequest.Builder()
  .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
  .build();

final NetworkRequest requestForEthernet =
  new NetworkRequest.Builder()
  .addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET)
  .build();

final ConnectivityManager connectivityManager = (ConnectivityManager)
  context.getSystemService(Context.CONNECTIVITY_SERVICE);

final NetworkCallback networkCallbackWifi = new NetworkCallback() {
  @Override
  void onAvailable(Network network) {
      // Triggers when this network is available so you can bind to it.
  }

  @Override
  void onLost(Network network) {
      // Triggers when this network is lost.
  }
};

final NetworkCallback networkCallbackEthernet = new NetworkCallback() {
  @Override
  void onAvailable(Network network) {
      // Triggers when this network is available so you can bind to it.
  }

  @Override
  void onLost(Network network) {
      // Triggers when this network is lost.
  }
};

connectivityManager.requestNetwork(requestForWifi, networkCallbackWifi);
connectivityManager.requestNetwork(requestForEthernet, networkCallbackEthernet);

然后,一旦回调触发,您就可以在相关代码(例如 OP 传输图像的代码)中监听 onAvailable(Network network) 并使用提供的 NetworkNetwork.OpenConnection() 进行连接到使用该网络的 HTTP 服务器。

这将允许您从同一个应用程序连接到两个独立的网络。