0

我正在开发一个android应用,我特别需要通过WiFi进行HTTP连接。在Android L及以上版本中,似乎有很多连接相关的变化。通过特定连接在android应用中发送流量

这是一段代码,我使用的是:

ConnectivityManager manager = (ConnectivityManager) 
ctx.getSystemService(Context.CONNECTIVITY_SERVICE); 
Network[] allNetworks = manager.getAllNetworks(); 

for(Network network : allNetworks) { 
    NetworkInfo info = manager.getNetworkInfo(network); 
    if(info.getType() == ConnectivityManager.TYPE_WIFI && info.getState() == NetworkInfo.State.CONNECTED) { 
    System.out.println("FOUND WIFI NETWORK!"); 

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 
    manager.bindProcessToNetwork(network); 
    } 

    app.network = network; 
    break; 
} 
} 

按ConnectivityManager和网络API文档,我应该能够做到networkObject.openConnection获得HttpURLConnection的约束,且网络。但我发现了这种类型的

W/System.err: java.net.SocketException: Binding socket to network 586 failed: EPERM (Operation not permitted) 
W/System.err:  at android.net.Network.bindSocket(Network.java:362) 
W/System.err:  at android.net.Network.bindSocket(Network.java:331) 
W/System.err:  at android.net.Network$NetworkBoundSocketFactory.createSocket(Network.java:182) 
W/System.err:  at com.android.okhttp.internal.http.SocketConnector.connectRawSocket(SocketConnector.java:155) 
W/System.err:  at com.android.okhttp.internal.http.SocketConnector.connectCleartext(SocketConnector.java:67) 
W/System.err:  at com.android.okhttp.Connection.connect(Connection.java:152) 
W/System.err:  at com.android.okhttp.Connection.connectAndSetOwner(Connection.java:185) 
W/System.err:  at com.android.okhttp.OkHttpClient$1.connectAndSetOwner(OkHttpClient.java:128) 
W/System.err:  at com.android.okhttp.internal.http.HttpEngine.nextConnection(HttpEngine.java:341) 
W/System.err:  at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:330) 
W/System.err:  at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:248) 
W/System.err:  at com.android.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:437) 
W/System.err:  at com.android.okhttp.internal.huc.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:114) 
W/System.err:  at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getOutputStream(HttpURLConnectionImpl.java:245) 
W/System.err:  at com.mypkg.myapp.utils.HttpRequestBackground.doInBackground(HttpRequestBackground.java:90) 
W/System.err:  at com.mypkg.myapp.utils.HttpRequestBackground.doInBackground(HttpRequestBackground.java:38) 
W/System.err:  at android.os.AsyncTask$2.call(AsyncTask.java:295) 
W/System.err:  at java.util.concurrent.FutureTask.run(FutureTask.java:237) 
W/System.err:  at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234) 
W/System.err:  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113) 
W/System.err:  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588) 
W/System.err:  at java.lang.Thread.run(Thread.java:818) 
W/System.err: Caused by: android.system.ErrnoException: Binding socket to network 586 failed: EPERM (Operation not permitted) 

的例外,这些东西都在清单

<uses-permission android:name="android.permission.INTERNET" /> 
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> 
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /> 
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> 
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" /> 
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> 

宣布与网络相关的权限,我不太理解什么是错在这里。

这样做的原因:Android不允许我在启用数据的情况下在我的应用中使用WiFi连接,并且与其连接的AP没有互联网。

回答

1

问题原来是因为在后台运行的VPN应用程序,它甚至发生在OkHttpClient之前,这似乎在工作。


我找到了使用OkHttpClient的解决方案。当使用network.openConnection时,基本上会出现某种错误,它会尝试绑定到端口< 1024,除非您是root用户,否则这在Linux中是不可能的。

虽然由于某种原因,如果我做了network.getSocketFactory()并将它传递给OkHttpClient,它的工作原理应该如此。

下面是一段代码我用来测试:

package com.nileshgr.networktest; 

import android.net.ConnectivityManager; 
import android.net.Network; 
import android.net.NetworkCapabilities; 
import android.net.NetworkRequest; 
import android.os.Bundle; 
import android.support.v7.app.AppCompatActivity; 

import java.io.IOException; 

import okhttp3.Call; 
import okhttp3.Callback; 
import okhttp3.OkHttpClient; 
import okhttp3.Request; 
import okhttp3.Response; 

public class MainActivity extends AppCompatActivity { 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 

     NetworkRequest.Builder requestbuilder = new NetworkRequest.Builder(); 
     requestbuilder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI); 

     ConnectivityManager cm = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE); 

     cm.requestNetwork(requestbuilder.build(), new ConnectivityManager.NetworkCallback() { 
      @Override 
      public void onAvailable(Network network) { 
       System.out.println("wifi network found"); 
       testSocket(network); 
      } 
     }); 
    } 

    private void testSocket(Network network) { 

     // client one, should go via wifi 
     OkHttpClient.Builder builder1 = new OkHttpClient.Builder(); 
     builder1.socketFactory(network.getSocketFactory()); 
     OkHttpClient client1 = builder1.build(); 
     Request request1 = new Request.Builder().url("http://text.whatisyourip.org").build(); 

     Callback cb = new Callback() { 
      @Override 
      public void onFailure(Call call, IOException e) { 
       e.printStackTrace(); 
      } 

      @Override 
      public void onResponse(Call call, Response response) throws IOException { 
       System.out.println("success"); 
       System.out.println(response.body().string()); 
      } 
     }; 

     System.out.println("sending via wifi network"); 

     client1.newCall(request1).enqueue(cb); 

     System.out.println("Sending via data network"); 

     // client 2 should go via data 
     OkHttpClient client2 = new OkHttpClient(); 
     Request request2 = new Request.Builder().url("http://text.whatisyourip.org").build(); 
     client2.newCall(request2).enqueue(cb); 
    } 
} 

您应该看到亚行对数两种不同的公共IP地址 - 一个Wi-Fi的公共IP地址和其他数据公网IP地址。但请确保在您连接的WiFi网络中,只允许text.whatsiyourip.org并阻止其他所有内容。如果你有一个具有多个SSID支持和防火墙的路由器,这是相当简单的。