2017-11-17 20 views
1

分散アプリケーションで、さまざまなホストが同じLAN内のローカルサーバーを見つける必要があります。AndroidでUDPデータグラムを使用して2つのプロセスと2つのホスト間で通信する方法

NsdManagerを使用してローカルサーバーを検出するのは成功していませんでしたが、この方法はサーバーには見られません。私はより良い解決策、より信頼できるものを探しています。

次に、UDPパケットをマルチキャストしようとしましたが、同じプロセス内で問題が検出されません。 (私の単体テストはクライアントインスタンスとサーバインスタンスの両方を使用します)。それはうまく動作します。同じクラスでは、クライアントが同じデバイス上で実行されているサーバーを検出できません(クライアントとサーバーは別々のプロセスアプリケーションです)。

次に、同じプロセス内でブロードキャストアドレスを使用してアプローチを変更しました。単体テストは問題ありませんが、2つの異なるプロセスではサーバーは見つかりませんでした。

前述のように、コードは同じプロセス内で正常に動作しますが、2つの異なるプロセス、または同じLAN内の2つの異なるクライアント/サーバーホストで動作する場合は機能しません。

注:私のLANはハイエンドのWiFiルーターであり、特別な設定はありません。

誰かが何か問題があるかもしれませんか?

私のマニフェストは、クライアントとサーバーの両方のアプリケーションのために、これらの設定が含まれていることを注意:

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

注同じホスト上で実行しているサーバーを検出するために、私のクライアントのために、私はすでにTCPソケットを使用していますが、私が必要とします自分のLANにあるサーバーを検出します。

+1

問題はあなたのコードにあります。 Q w.r.t [mcve](https://stackoverflow.com/help/mcve)を編集します。 UDP通信は、どんな種類のプロセスにも依存することができません。 – Onik

+0

私のコードは、クライアントとサーバーの両方が同じプロセス内で動作しているユニットテスト内にある限り、マルチキャストパケットとブロードキャストUDPパケットの両方でうまく動作します。したがって、2つの別々のクライアントとサーバーアプリケーションを実行すると、2つの別々のプロセスがあり、私のコードはデータグラムを読み取ることができません。 – Bamaco

+0

正確に同じコードは、サーバーとクライアントの両方が同じプロセスに存在する場合にデータグラムを読み取ります。問題は、両方のアプリケーションが別々のホストとアプリケーションで実行されている場合です。 – Bamaco

答えて

1

UDP通信は、プロセスの任意の種類に依存することはできません。問題はあなたのコードにあります。

1

@Onikはかなり正しかった、ミニマル完全、かつ検証例を作る

は私が問題を発見することができました。ここで

は興味がある可能性が誰のためのコードです:

package com.example; 

import java.net.DatagramPacket; 
import java.net.DatagramSocket; 
import java.net.InetAddress; 
import java.net.InterfaceAddress; 
import java.net.NetworkInterface; 
import java.util.Enumeration; 
import java.util.List; 

import android.util.Log; 

/** 
* Minimal, Complete, and Verifiable example for broadcasting UDP sockets, send thread. 
* 
* Loosely based on: 
* 
* https://jackiexie.com/2015/07/15/network-discovery-using-udp-broadcast-java/ 
*/ 
public class BroadcastSender extends Thread { 

public static final String TAG = "BroadcastSender"; 

public static final int TEST_PORT_NUMBER   = 1234; 
public static final int TEST_COUNT     = 10; 
public static final int DELAY_BETWEEN_PACKETS_MS = 500; 

public static final int TEST_TIME_MS = TEST_COUNT * DELAY_BETWEEN_PACKETS_MS; 

private DatagramSocket mSocket; 

public BroadcastSender() { 

    super(TAG); 
} 

public static InetAddress getBroadcastAddress() { 

    try { 
     Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces(); 

     while(interfaces.hasMoreElements()) { 

      NetworkInterface current = interfaces.nextElement(); 

      try { 

       if(!current.isUp() ) 
        continue; 

       if(current.isLoopback()) 
        continue; 

       List<InterfaceAddress> addresses = current.getInterfaceAddresses(); 

       if(addresses == null) { 

        log("getBroadcastAddress can not get addresses from "+current);      
        continue; 
       } 

       for(InterfaceAddress oneInterfaceAddress : addresses) { 

        InetAddress bcast = oneInterfaceAddress.getBroadcast(); 

        if(bcast != null) 
         return bcast; 
       } 
      } 
      catch(Exception ex) { 

       log("getBroadcastAddress exception "+ex+" stack "+Log.getStackTraceString(ex)); 
      }    
     } 
    } 
    catch(Exception ex) { 

     log("getBroadcastAddress exception "+ex+" stack "+Log.getStackTraceString(ex)); 
    } 

    return null; 
}  

@Override 
public void run() { 

    try { 

     mSocket = new DatagramSocket(); 
     mSocket.setBroadcast(true);   

     InetAddress interfaceBroadcast = getBroadcastAddress(); 

     InetAddress broadcastAddr = InetAddress.getByName("255.255.255.255");     

     String payloadStr = "payload pid="+android.os.Process.myPid(); 
     byte payloadBytes[] = payloadStr.getBytes(); 

     for(int packet = 0; packet < TEST_COUNT; packet++) { 

      // First send to 255.255.255.255 
      DatagramPacket dp = new DatagramPacket(payloadBytes, payloadBytes.length, broadcastAddr, TEST_PORT_NUMBER);  
      mSocket.send(dp); 

      // Then send to whatever address we have for interfaceBroadcast 
      if(interfaceBroadcast != null) { 

       dp = new DatagramPacket(payloadBytes, payloadBytes.length, interfaceBroadcast, TEST_PORT_NUMBER); 
       mSocket.send(dp); 
      } 

      log("sent #"+packet+" with "+payloadBytes.length+" bytes \""+payloadStr+"\""); 

      synchronized (this) { 

       try { 

        wait(DELAY_BETWEEN_PACKETS_MS); 
       } 
       catch(InterruptedException ex) { 

        log("run exeption "+ex.toString()); 
       } 
      } 
     } 

     mSocket.close();    
     mSocket = null;     
    } 
    catch(Exception ex) { 

     log("run exception "+ex.toString()+" stack "+Log.getStackTraceString(ex)); 
    } 
} 

private static void log(String message) { 

    Log.d(TAG, message); 
} 


/** 
* Minimal, Complete, and Verifiable example for broadcasting UDP sockets, receive thread. 
* Loosely based on: 
* 
* https://jackiexie.com/2015/07/15/network-discovery-using-udp-broadcast-java/ 
*/ 
public static class BroadcastReceiver extends Thread { 

    public static final String TAG = "BroadcastReceiver"; 

    public int totalReceived = 0; 

    public BroadcastReceiver() { 

     super(TAG); 
    } 

    @Override 
    public void run() { 

     final String methodName = "run"; 

     try { 

      byte messageBytes[] = new byte[1500]; 

      DatagramPacket dp = new DatagramPacket(messageBytes, messageBytes.length); 

      DatagramSocket mSocket = new DatagramSocket(TEST_PORT_NUMBER); 
      mSocket.setSoTimeout(DELAY_BETWEEN_PACKETS_MS); 
      mSocket.setBroadcast(true); 

      while(totalReceived < TEST_COUNT) { 

       try {      
        // Get one UDP packet 
        mSocket.receive(dp); 

        if(dp.getLength() > 0) { 

         totalReceived++; 

         String payloadStr = new String(dp.getData()); 
         log("received #"+totalReceived+" : \""+payloadStr+"\""); 
        }     
       } 
       catch(Exception ex) { 

        log("receive exception "+ex.toString()); 
       } 
      }    

      mSocket.close();    
      mSocket = null;    
      log(methodName+" socket closed."); 
     } 
     catch(Exception ex) { 

      log(methodName+" exception "+ex.toString()); 
     } 
    } 

    private static void log(String message) { 

     Log.d(TAG, message); 
    } 
} 

public static boolean unit_test() { 

    try { 

     BroadcastSender  sender = new BroadcastSender(); 
     sender.start(); 

     BroadcastReceiver receiver = new BroadcastReceiver(); 
     receiver.start(); 
     log("joining "+sender.getName()); 
     sender.join(TEST_TIME_MS); 

     log("joining "+receiver.getName()); 
     receiver.join(TEST_TIME_MS); 

     boolean success = receiver.totalReceived >= TEST_COUNT; 
     log("unit test results="+success); 
     return success; 

    } 
    catch(Exception ex) { 

     log("unit test exception "+ex); 
     return false; 
    } 
} 
/* 
* Log output: 
* 
D 2017-11-17 19:10:56.809 6228 BroadcastSender sent #0 with 16 bytes "payload pid=6228" 
D 2017-11-17 19:10:57.313 6228 BroadcastSender sent #1 with 16 bytes "payload pid=6228" 
D 2017-11-17 19:10:57.314 6228 BroadcastReceiver received #1 : "payload pid=6228" 
D 2017-11-17 19:10:57.315 6228 BroadcastReceiver received #2 : "payload pid=6228" 
D 2017-11-17 19:10:57.816 6228 BroadcastSender sent #2 with 16 bytes "payload pid=6228" 
D 2017-11-17 19:10:57.817 6228 BroadcastReceiver received #3 : "payload pid=6228" 
D 2017-11-17 19:10:57.818 6228 BroadcastReceiver received #4 : "payload pid=6228" 
D 2017-11-17 19:10:58.319 6228 BroadcastReceiver received #5 : "payload pid=6228" 
D 2017-11-17 19:10:58.319 6228 BroadcastSender sent #3 with 16 bytes "payload pid=6228" 
D 2017-11-17 19:10:58.321 6228 BroadcastReceiver received #6 : "payload pid=6228" 
D 2017-11-17 19:10:58.822 6228 BroadcastSender sent #4 with 16 bytes "payload pid=6228" 
D 2017-11-17 19:10:58.822 6228 BroadcastReceiver received #7 : "payload pid=6228" 
D 2017-11-17 19:10:58.823 6228 BroadcastReceiver received #8 : "payload pid=6228" 
D 2017-11-17 19:10:59.325 6228 BroadcastReceiver receive exception java.net.SocketTimeoutException: Receive timed out 
D 2017-11-17 19:10:59.326 6228 BroadcastReceiver received #9 : "payload pid=6228" 
D 2017-11-17 19:10:59.327 6228 BroadcastReceiver received #10 : "payload pid=6228" 
D 2017-11-17 19:10:59.325 6228 BroadcastSender sent #5 with 16 bytes "payload pid=6228" 
D 2017-11-17 19:10:59.328 6228 BroadcastReceiver run socket closed. 
D 2017-11-17 19:10:59.831 6228 BroadcastSender sent #6 with 16 bytes "payload pid=6228" 
D 2017-11-17 19:11:00.333 6228 BroadcastSender sent #7 with 16 bytes "payload pid=6228" 
D 2017-11-17 19:11:00.834 6228 BroadcastSender sent #8 with 16 bytes "payload pid=6228" 
D 2017-11-17 19:11:01.336 6228 BroadcastSender sent #9 with 16 bytes "payload pid=6228" 
D 2017-11-17 19:11:01.839 6228 BroadcastSender sent #10 with 16 bytes "payload pid=6228" 
D 2017-11-17 19:11:02.341 6228 BroadcastSender sent #11 with 16 bytes "payload pid=6228" 
D 2017-11-17 19:11:02.844 6228 BroadcastSender sent #12 with 16 bytes "payload pid=6228" 
D 2017-11-17 19:11:03.346 6228 BroadcastSender sent #13 with 16 bytes "payload pid=6228" 
D 2017-11-17 19:11:01.810 6228 BroadcastSender unit test results=true 
*/ 
} 
関連する問題