2017-11-17 2 views
1

Meine verteilte Anwendung, mit verschiedenen Hosts müssen lokale Server innerhalb des gleichen LAN finden.Wie zwischen zwei Prozess und zwei Hosts mit UDP-Datagramme auf Android kommunizieren

Ich hatte begrenzte Erfolgserkennung lokale Server mit NsdManager, das ist der Weg zu gehen, aber oft bleiben Server unerkannt. Ich suche nach einer besseren Lösung, etwas zuverlässiger.

Dann habe ich versucht, UDP-Pakete Multicasting, die ich habe kein Problem von innerhalb des gleichen Prozesses erkennen. (Mein Komponententest verwendet sowohl Client- als auch Serverinstanzen). Das funktioniert gut. Die gleichen Klassen erlauben es meinen Clients nicht, meine Server zu erkennen, die auf demselben Gerät laufen (Client und Server sind separate Prozessanwendungen).

Dann änderte ich meinen Ansatz mit Broadcast-Adressen, wiederum innerhalb desselben Prozesses, Unit Tests sind in Ordnung, aber in zwei verschiedenen Prozess, kein Server gefunden.

Wie gesagt, der Code funktioniert innerhalb desselben Prozesses, aber er funktioniert nicht, wenn er in zwei verschiedenen Prozessen oder auf zwei verschiedenen Client/Server-Hosts im selben LAN ausgeführt wird.

Hinweis: mein LAN ist ein High-End WiFi Rooter, keine speziellen Einstellungen.

Jeder hat eine Ahnung, was könnte das Problem sein?

Beachten Sie, dass mein Manifest diese Einstellungen für Client- und Server-Anwendungen umfasst:

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

Beachten Sie, dass für meine Client den Server auf demselben Host-zu erkennen, ich bin schon TCP-Sockets verwenden, aber ich brauche um festzustellen, welcher Server in meinem LAN ist.

+1

Das Problem ist in Ihrem Code. Bearbeiten Sie Ihr Q wr.t [mcve] (https://stackoverflow.com/help/mcve). UDP-Kommunikation kann nicht von irgendwelchen Prozessen abhängen. – Onik

+0

Mein Code funktioniert gut, sowohl mit Multicast- als auch mit gesendeten UDP-Paketen, solange es sich innerhalb meiner Komponententests befindet, bei denen sowohl der Client als auch der Server innerhalb desselben Prozesses ausgeführt werden. Wenn zwei separate Client- und Serveranwendungen ausgeführt werden, also zwei getrennte Prozesse, kann mein Code keine Datagramme lesen. – Bamaco

+0

Exact gleichen Code liest Datagramme gut, wenn Server und Client beide im selben Prozess leben. Das Problem tritt auf, wenn beide Anwendungen in separaten Hosts und Anwendungen ausgeführt werden. – Bamaco

Antwort

1

UDP-Kommunikation nicht auf jede Art von Prozessen abhängen. Das Problem liegt in Ihrem Code.

1

@Onik ganz richtig war,

ein Minimal, Complete, und prüfbare Beispiel macht mir erlaubt, das Problem zu finden. Hier

ist der Code für wen auch immer interessieren:

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 
*/ 
} 
Verwandte Themen