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支持和防火牆的路由器,這是相當簡單的。