2016-11-04 18 views
1

みんな! 私はこのアプリをインストールした近くのデバイスとチャットできるAndroidアプリを開発しています。これを達成するために、Wi-Fi P2P APIとネットワークサービスディスカバリを使用して、近くのデバイスを検索しています。 サービスによって開始されたスレッド内の近くのデバイスを検索するためのコードを記述しました。デバイスが検出されると、サービスはこれまでに検出されたデバイスを表示するアクティビティに(ブロードキャストインテントを介して)送信します。 検出されたデバイスはrecyclerViewに追加され、ユーザがそれらのいずれかを押すと、そのデバイスに接続する必要があります。 Wi-Fi Direct接続が正常に確立されます(つまり、WifiP2pManager.connect()メソッドが成功します)、WIFI_P2P_CONNECTION_CHANGED_ACTIONが捕捉されます。私はこのようなデバイスIのIPアドレスとして、接続の詳細情報を取得することができるrequestConnectionInfo()メソッドでWi-Fi P2Pによるネットワークサービスディスカバリを使用しているときにAndroidデバイスに接続できません

NetworkInfo networkInfo = (NetworkInfo) intent.getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO); 
      if (networkInfo.isConnected()) { 

       mManager.requestConnectionInfo(mChannel, connectionInfoListener); } 

:放送受信装置は、このような放送意図がキャッチされたときに、次のコードが実行されるで に接続しようとしています。 このような情報を得るために、私はそのメソッドにWifiP2pManager.ConnectionInfoListenerの実装を提供します。これはconnectionInfoListener変数で表されます。 これはWifiP2pManager.ConnectionInfoListenerの私の実装のコードです:

​​

「デバイス」は今重要ではありませんBroadcastReceiverの私の実装のインスタンス変数です。代わりに重要なのは、ConnectThreadスレッドです。これは、2つのデバイス間でソケットを接続するために必要なコードを処理するスレッドです。私が検出されたデバイス、ConnectThread、その実行で()メソッドに接続しようとすると、IPアドレスと以前にこのコンストラクタに取得したポート番号を渡すChatConnectionの新しいインスタンスを作成します。

public ChatConnection(InetAddress srvAddress, int srvPort, String macAddress) throws IOException { 
     ... 

     connSocket = new Socket(srvAddress, srvPort); 

     ... 

    } 

そしてここはどこです問題が発生します。私は私の物理デバイス上で自分のアプリケーションをテストするときは、私が得るすべてはこの例外である:もちろん

W/System.err: java.net.ConnectException: failed to connect to /192.168.49.1 (port 6770): connect failed: ECONNREFUSED (Connection refused) 

、私は正常に検出されたとのWi-Fiダイレクト接続が取得されますあまりにも第二の物理デバイス上に私のアプリをインストール成功したしかし、このコード行に来るとき:

例外がスローされ
connSocket = new Socket(srvAddress, srvPort); 

... 私はこの質問の長さをお詫び申し上げますが、私は明確な可能になりたかったです。 事前にお手伝いいただき、本当にありがとうございます。

EDIT: ServerSocketを初期化するコードについては忘れていました。
ServerSocketは、Wi-Fiが有効になるとすぐに開始されるスレッドで初期化されます。
つまり、BroadcastReceiverを拡張するAppサービスの内部クラスであるWifiP2pBroadcastReceiverがWIFI_P2P_STATE_CHANGED_ACTIONインテントをキャッチすると、Wi-Fiが有効になっているかどうかをチェックし、有効になっている場合は、ServerSocketがあるスレッドを開始します。サーバーソケットとして宣言

public void run() { 
     ... 

     try { 
      server = new ServerSocket(0); 
     } catch (IOException ex) { 

      return; 
     } 

     ... 

     while (!Thread.currentThread().isInterrupted()) { 

      Socket clientSocket = null; 
      try { 
       clientSocket = server.accept(); 
      } catch (IOException ex) { 

       break; 
      } 
      try { 

       ChatConnection chatConn = new ChatConnection(clientSocket); 
       synchronized (connections) { 
        connections.add(chatConn); 
       } 

      } catch (IOException ex) { 

       continue; 
      } 
     } 

"サーバ" NsdProviderThreadのインスタンス変数である:

public void onReceive(Context context, Intent intent) { 

     String action = intent.getAction(); 

     if (action.equals(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION)) { 

      int statoWiFi = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1); 
      if (statoWiFi == WifiP2pManager.WIFI_P2P_STATE_ENABLED) { 

       mNsdService = new NsdProviderThread(); 
       mNsdService.start(); 
      } 

のServerSocketをNsdProviderThreadのrun()メソッドで初期化されているが。

+1

あなたは他のデバイスからのソケット接続を受け入れるためのServerSocketを必要とする.... –

+0

私はあなたのコメントに感謝します。私はちょうど私の質問を編集し、ServerSocketに関するより多くの情報を追加しました。 – Nilio

答えて

0

あなただけの両端で正しいポート番号を使用する必要があるように見えます。

あなたはthe documentationから意味し、ゼロを使用している:

0のポート番号は、ポート番号が自動的に一般的にエフェメラルポートの範囲から、割り当て であることを意味します。

あなたのServerSocketを作成するときに、他のデバイスが接続を開始するために使用するのと同じポートで待機していることを確認してください:再び

private static final int port = 6770; 

//..... 

try { 
    server = new ServerSocket(port); 
} catch (IOException ex) { 
    ex.printStackTrace(); 
} 
+0

私はこのようにServerSocketのポート番号をハードコーディングしようとしました: server = new ServerSocket(6770); そして私はChatConnectionのコンストラクタで同じことをしました: connSocket = new Socket(srvAddress、6770); アプリケーションがそのコード行に来ると、例外はもうスローされませんが、接続が確立されるのを永遠に待つような、アプリケーションはちょうどそこに(エラーも例外もなく)ハングします... – Nilio

0

を!ついに私のアプリが動くようになった。ここに私がしたことがあります:

  • ハードコードのポート番号;
  • あなたはConnectionInfoListener実装におけるグループ所有者のアドレスを取得すると、それは、使用中のデバイスのIPアドレスがある場合は、確認してください。そうでない場合は、クライアントソケットをグループ所有者アドレスに接続します。それ以外の場合は、着信接続を待つようにします。
  • (アプリが起動したとき、たとえば)できるだけ早くServerSocketをを初期化します。

のWi-Fiダイレクト接続が確立された後にデバイスの実際のIPアドレスを取得するためには、私は(元のAndroid WiFiDirectdemoによって導出される)thisプロジェクトで見つけたこの機能を使用しました"Utilsの" クラス:

public static String getLocalIPAddress() { 
    /* 
    * modified from: 
    * 
    * http://thinkandroid.wordpress.com/2010/03/27/incorporating-socket-programming-into-your-applications/ 
    * 
    * */ 
    try { 
     for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) { 
      NetworkInterface intf = en.nextElement(); 
      for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();) { 
       InetAddress inetAddress = enumIpAddr.nextElement(); 

       String iface = intf.getName(); 
       if(iface.matches(".*" +p2pInt+ ".*")){ 
        if (inetAddress instanceof Inet4Address) { // fix for Galaxy Nexus. IPv4 is easy to use :-) 
         return getDottedDecimalIP(inetAddress.getAddress()); 
        } 
       } 
      } 
     } 
    } catch (SocketException ex) { 
     Log.e("AndroidNetworkAddressFactory", "getLocalIPAddress()", ex); 
    } catch (NullPointerException ex) { 
     Log.e("AndroidNetworkAddressFactory", "getLocalIPAddress()", ex); 
    } 
    return null; 
} 

"p2pIntは" とUtilsのクラスで宣言されたプライベート静的文字列costantです:

private final static String p2pInt = "p2p-p2p0" 

しかし、私のアプリでは、私は「P2Pを変更しました「p2p-wlan0」の「-p2p0」文字列Wi-Fi Direct用のデバイスのネットワークインターフェイスに(別の)名前が付いているようだからです。 私は、これはのWi-Fiダイレクト接続を使用してアプリケーションを作成しようとしているすべての開発者を助けることができると思います。

関連する問題