2013-06-25 5 views
11

Sto provando a sviluppare un'applicazione che invia alcuni messaggi broadcast e riceve alcune risposte dagli altri dispositivi Android. Sto avendo qualche problema a ricevere i messaggi UDP dagli altri dispositivi. Dovrei menzionare che questo codice ha funzionato su Gingerbread ma su JellyBean non funziona più e non so quale potrebbe essere il problema.Invia broadcast UDP ma non lo riceve su altri dispositivi Android

qui è dove io mando il messaggio di trasmissione (so che gli altri dispositivi in ​​ascolto sulla porta 5000):

private void sendUDPMessage(String msg) { 

    try { 
     DatagramSocket clientSocket = new DatagramSocket(); 

     clientSocket.setBroadcast(true); 
     InetAddress address = InetAddress.getByName(Utils.getBroadcastAddress()); 

     byte[] sendData; 

     sendData = msg.getBytes(); 
     DatagramPacket sendPacket = new DatagramPacket(sendData, 
       sendData.length, address, 5000); 
     clientSocket.send(sendPacket); 

     clientSocket.close(); 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 

} 

E qui è dove lo ricevo:

private void start_UDP() 
{ 
    try { 
      serverSocketUDP = new DatagramSocket(5000); 
     } 
    catch (Exception e) { 

     Log.i(LOGTAG, "Exception opening DatagramSocket UDP"); 
    } 

    final byte[] receiveData = new byte[1024]; 


    while(runningUDP) { 
     Log.d(LOGTAG, "Waiting for Broadcast request in ServerUDP."); 

     final DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length); 

     serverSocketUDP.receive(receivePacket); 


       byte[] sendData = new byte[1024]; 
       InetAddress address = receivePacket.getAddress(); 
       int port = receivePacket.getPort(); 
       if(!receivePacket.getAddress().getHostAddress().equals(Utils.getLocalIpAddress())) 
       { 
        String req = new String(receivePacket.getData(), 0, receivePacket.getLength()); 


        Log.d(LOGTAG, "Received UDP message : "+req+" from: "+receivePacket.getAddress().getHostAddress()); 
       } 
         }// while ends 
     }//method ends 

Devo dire che queste 2 funzioni sono separate in 2 diversi thread, quindi posso inviare e ricevere simultaneamente.

Ho anche acquisire le seguenti serrature:

powerManager =(PowerManager)context.getSystemService(Context.POWER_SERVICE); 
    wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK ,LOGTAG); // PARTIAL_WAKE_LOCK Only keeps CPU on 
    wifiManager = (WifiManager)context.getSystemService(Context.WIFI_SERVICE); 
    wifiLock = wifiManager.createWifiLock(3, LOGTAG); 
    multicastLock = wifiManager.createMulticastLock(LOGTAG); 

    wakeLock.acquire(); 
    multicastLock.acquire(); 
    wifiLock.acquire(); 

E i permessi sul file manifesto:

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

Ho testato se i messaggi sono inviati utilizzando Wireshark e tcpdump e vengono inviati. Inoltre, ciò che è ancora più strano, ricevo i messaggi broadcast che invio (ma li scarto perché non ho bisogno di elaborare i messaggi inviati da me) ma non ricevo i messaggi broadcast inviati dagli altri dispositivi (che dovrebbero avere il stesso formato, solo l'indirizzo di origine sarebbe diverso e il messaggio contenuto, in entrambi i casi non dovrebbe influire sul messaggio broadcast).

Per favore fatemi sapere se avete qualche idea perché ho davvero esaurito qualsiasi altra cosa potrei provare. Qualsiasi aiuto sarebbe apprezzato. Grazie!

EDIT: ho fatto alcuni test e anche se quando ho eseguito su ciascuno dei wlan0 telefoni ifconfig e si dice qualcosa come

ifconfig wlan0 
    wlan0: ip 169.254.17.28 mask 255.255.0.0 flags [up broadcast multicast] 

il che significa che l'interfaccia è attiva e il PI è impostato e può ricevere messaggi broadcast e msg multicast ma quando uso

    InetAddress in=InetAddress.getByName("169.254.17.28"); 
      if (in.isReachable(1000)) 
       Log.i(LOGTAG, "host is reachable"); 
      else 
       Log.i(LOGTAG, "host is not reachable"); 

Mostra nei registri che l'host non è raggiungibile.

Questo è dove accendo il Wi-fi

private void startWifiAdhoc() { 

    WifiManager wifiManager =  (WifiManager)SharingFileService.context.getSystemService(Context.WIFI_SERVICE); 
    String command=""; 
    if (condWifiAdhoc == false) { 

     condWifiAdhoc=true; 
     wifiInterface = Utils.getWifiInterface(); 


     wifiManager.setWifiEnabled(true); 
     localIP = Utils.getLinkLocalAddress(); 
    } 
    else 
    { 
     wifiManager.setWifiEnabled(true); 
     localIP = Utils.getLinkLocalAddress(); 
    } 
     // Set wifi ad-hoc 
     command = context.getFilesDir().getPath() 
       + "/iwconfig " + wifiInterface + " mode ad-hoc essid " 
       + "mcp" + " channel " + "1" + " commit\n"; 

     Log.i(LOGTAG, command); 
     Utils.rootExec(command); 


     Log.i(LOGTAG, "Ip address used :" + localIP); 
     command = context.getFilesDir().getPath() 
       + "/ifconfig " + wifiInterface + " " + localIP 
       + " netmask 255.255.0.0 up\n"; 



     Log.i(LOGTAG, command); 
     Utils.rootExec(command); 

} 
+0

Nota che alcuni i router disabilitano il DNS multicast per impostazione predefinita. – yorkw

+0

oh ... Devo dire che sono in un wifi ad hoc – Lara

+0

Si consiglia di guardare questo post: http://stackoverflow.com/a/16208617/1028256 Si dice che alcuni driver wifi possono disabilitare i ricevitori di trasmissione, ma in tal caso accade dopo aver ripreso dalla modalità di sospensione. – Mixaz

risposta

1

mi sono imbattuto tuo post quando si cerca di risolvere un problema simile. Hai messo al lavoro le tue cose?

Nel mio caso, stavo cercando di ottenere un Nexus 7 (primo gen con Jelly Bean 4.3) e Nexus One (Gingerbread 2.3.6) che parlano tra loro tramite UDP. Inizialmente la mia app, in esecuzione su entrambi i dispositivi, sarebbe riuscita a collegarsi, ma solo con una comunicazione unidirezionale dal telefono al tablet. Avevo un solo permesso sul manifest: INTERNET. La comunicazione dal tablet al telefono ha iniziato a funzionare dopo aver aggiunto l'autorizzazione ACCESS_NETWORK_STATE al manifest.

Quindi, per qualche motivo, il Nexus 7 è felice solo con l'autorizzazione INTERNET sia per l'invio e la ricezione di pacchetti UDP (beh, la mia particolare implementazione di esso, almeno).Il Nexus One invierà solo con l'autorizzazione INTERNET ma non riceverà a meno che non venga data l'autorizzazione ACCESS_NETWORK_STATE.

Il tuo codice è simile al mio (non riconosco le chiamate "UTILS", tuttavia). Nel mio caso, però, ai fini del test, ho codificato l'indirizzo di broadcast (192.168.n.255). Sono su un punto di accesso mentre sei su una rete ad hoc. Forse ha anche qualche effetto.

12

ho ottenuto questo lavoro utilizzando un metodo descritto qui per calcolare l'indirizzo di broadcast: https://code.google.com/p/boxeeremote/wiki/AndroidUDP

Ecco il mio ricevitore:

try { 
    //Keep a socket open to listen to all the UDP trafic that is destined for this port 
    socket = new DatagramSocket(Constants.PORT, InetAddress.getByName("0.0.0.0")); 
    socket.setBroadcast(true); 

    while (true) { 
    Log.i(TAG,"Ready to receive broadcast packets!"); 

    //Receive a packet 
    byte[] recvBuf = new byte[15000]; 
    DatagramPacket packet = new DatagramPacket(recvBuf, recvBuf.length); 
    socket.receive(packet); 

    //Packet received 
    Log.i(TAG, "Packet received from: " + packet.getAddress().getHostAddress()); 
    String data = new String(packet.getData()).trim(); 
    Log.i(TAG, "Packet received; data: " + data); 

    // Send the packet data back to the UI thread 
    Intent localIntent = new Intent(Constants.BROADCAST_ACTION) 
      // Puts the data into the Intent 
      .putExtra(Constants.EXTENDED_DATA_STATUS, data); 
    // Broadcasts the Intent to receivers in this app. 
    LocalBroadcastManager.getInstance(this).sendBroadcast(localIntent); 
    } 
} catch (IOException ex) { 
    Log.i(TAG, "Oops" + ex.getMessage()); 
} 

Ed ecco il mio mittente:

public void sendBroadcast(String messageStr) { 
    // Hack Prevent crash (sending should be done using an async task) 
    StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build(); 
    StrictMode.setThreadPolicy(policy); 

    try { 
     //Open a random port to send the package 
     DatagramSocket socket = new DatagramSocket(); 
     socket.setBroadcast(true); 
     byte[] sendData = messageStr.getBytes(); 
     DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, getBroadcastAddress(), Constants.PORT); 
     socket.send(sendPacket); 
     System.out.println(getClass().getName() + "Broadcast packet sent to: " + getBroadcastAddress().getHostAddress()); 
    } catch (IOException e) { 
     Log.e(TAG, "IOException: " + e.getMessage()); 
    } 
    } 

    InetAddress getBroadcastAddress() throws IOException { 
    WifiManager wifi = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); 
    DhcpInfo dhcp = wifi.getDhcpInfo(); 
    // handle null somehow 

    int broadcast = (dhcp.ipAddress & dhcp.netmask) | ~dhcp.netmask; 
    byte[] quads = new byte[4]; 
    for (int k = 0; k < 4; k++) 
     quads[k] = (byte) ((broadcast >> k * 8) & 0xFF); 
    return InetAddress.getByAddress(quads); 
    } 
+0

Questo codice funziona solo se i dispositivi si trovano sulla stessa rete locale? – zer0uno

+0

Sì, corretto – caspii

+0

verificato su Android 5.1.1 e Android 7.1.2 –