0

Wi-Fi를 통해 특별히 HTTP 연결을해야하는 Android 앱을 개발 중입니다. Android L 이상에서 많은 연결 관련 변경 사항이있는 것으로 보입니다. 나는 HttpURLConnection의 해당 네트워크를 결합 얻을 networkObject.openConnection을 할 수 있어야 ConnectivityManager 및 네트워크 API 문서 당으로특정 연결을 통해 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; 
} 
} 

:

은 내가 사용하고 코드의 조각이다. 하지만이 유형

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" /> 

에 선언 된 네트워크 관련 권한입니다.

이유 : 안드로이드는 데이터가 사용 가능하고 연결된 AP에 인터넷이 없는데도 내 앱에서 Wi-Fi 연결을 허용하지 않습니다.

답변

1

백그라운드에서 실행 중이던 VPN 응용 프로그램 때문에 문제가 발생했으며 이전에 작동했던 것처럼 보이던 OkHttpClient에서도 문제가 발생했습니다.


나는 OkHttpClient를 사용하여 솔루션을 발견했다. 기본적으로 network.openConnection을 사용하면 루트가 아닌 한 리눅스에서 불가능한 포트 < 1024에 바인딩하려고 시도 할 때 버그가 발생합니다.

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); 
    } 
} 

당신은 ADB 로그에 두 개의 서로 다른 공용 IP 주소를 볼 수 - 하나의 무선 랜 공용 IP 주소 및 기타 데이터 공용 IP 주소를 입력합니다. 하지만 당신이 연결되어있는 와이파이 네트워크에서 text.whatsiyourip.org 만 허용하고 다른 모든 것들을 차단하십시오. 다중 SSID 지원 및 방화벽 기능이있는 라우터를 사용하는 것이 쉽습니다.