web-dev-qa-db-fra.com

Envoyez la diffusion UDP mais ne la recevez pas sur d'autres appareils Android

J'essaie de développer une application qui envoie des messages à diffusion générale et reçoit des réponses des autres appareils Android. Je ne parviens pas à recevoir les messages UDP des autres appareils. Je devrais mentionner que ce code a fonctionné sur Gingerbread mais sur JellyBean, il ne fonctionne plus et je ne sais pas quel pourrait être le problème.

Voici où j'envoie le message de diffusion (je sais que les autres périphériques écoutent sur le port 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();
    }

}

Et voici où je le reçois:

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

Je dois mentionner que ces 2 fonctions sont séparées dans 2 threads différents afin que je puisse envoyer et recevoir simultanément.

J'acquiers également les serrures suivantes:

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

Et les autorisations sur le fichier Manifest: 

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

J'ai testé si les messages sont envoyés en utilisant Wireshark et tcpdump et ils sont envoyés. De plus, ce qui est encore plus étrange, je reçois les messages de diffusion que j’envoie (mais je les rejette car je n’ai pas besoin de traiter les messages envoyés par moi-même) mais je ne reçois pas les messages de diffusion envoyés par les autres appareils (qui devraient avoir la même format, seule l’adresse source serait différente et le message contenu (l’une ou l’autre des manières ne devrait pas affecter le message diffusé).

S'il vous plaît, faites-moi savoir si vous avez des idées car je suis vraiment à court de tout ce que je pourrais essayer. Toute aide serait appréciée. Merci!

EDIT: J'ai fait quelques tests et même si je tourne sur chacun des téléphones ifconfig wlan0 et que ça dit quelque chose comme 

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

ce qui signifie que l'interface est active et que l'adresse IP est définie et peut recevoir des messages de diffusion et des messages de multidiffusion, mais lorsque j'utilise

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

Il montre dans les journaux que l'hôte n'est pas accessible.

C'est ici que j'allume le 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);

}
13
Lara

Cela fonctionne en utilisant une méthode décrite ici pour calculer l'adresse de diffusion: https://code.google.com/p/boxeeremote/wiki/AndroidUDP

Voici mon récepteur:

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

Et voici mon expéditeur:

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

Je suis tombé sur votre message en essayant de résoudre un problème similaire. Avez-vous fait fonctionner vos affaires?

Dans mon cas, j'avais essayé de faire parler un Nexus 7 (première génération avec Jelly Bean 4.3) et un Nexus One (Gingerbread 2.3.6) via UDP. Au départ, mon application, fonctionnant sur les deux appareils, serait correctement connectée, mais uniquement avec une communication à sens unique du téléphone à la tablette. Je n'avais qu'une seule permission en place dans le manifeste: INTERNET. La communication entre la tablette et le téléphone a commencé à fonctionner une fois que j'ai ajouté l'autorisation ACCESS_NETWORK_STATE au manifeste. 

Donc, pour une raison quelconque, le Nexus 7 est satisfait de l’autorisation INTERNET pour l’envoi et la réception de paquets UDP (enfin, ma mise en œuvre particulière, du moins). Le Nexus One envoie uniquement avec le droit INTERNET, mais ne le recevra que si le droit ACCESS_NETWORK_STATE est également attribué.

Votre code est similaire au mien (je ne reconnais pas vos appels "UTILS.", Cependant). Dans mon cas, cependant, aux fins de test, j'ai codé en dur l'adresse de diffusion (192.168.n.255). Je suis sur un point d'accès alors que vous êtes sur un réseau ad hoc. Cela a peut-être aussi un effet.

1
UpLate