Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
957 views
in Technique[技术] by (71.8m points)

networking - Android send udp broadcast silently fails

I want to implement service discovery by using the network's broadcast address. I am sniffing packets with WireShark to confirm that my UDP packets are not being sent. The network code is not being run on the UI thread. The DatagramSocket.send call returns with no exception thrown, but nothing is seen by other programs including WireShark. I have verified that the address returned by getWifiBroadcastAddress actually is the broadcast address of my network.

I have verified that the network supports broadcast by writing a C# program, run on another machine, and WireShark is detecting broadcast packets from this program.

Here is my Android Java code:

try {
    DatagramSocket socket = new DatagramSocket(Protocol.INQUIRY_PORT);
    socket.setBroadcast(true);
    InetAddress broadcastAddr = getWifiBroadcastAddress();

    byte[] data = new byte[10];
    for(int i = 0; i < data.length; i++) {
        data[i] = (byte) i;
    }

    DatagramPacket packet = new DatagramPacket(data, data.length,
            broadcastAddr, Protocol.INQUIRY_PORT);
    while(true) {
        // Loops indefinitely, no errors/exceptions
        socket.send(packet);
        try {
            Thread.sleep(5000);
        } catch(InterruptedException ie) {
            break;
        }
    }
} catch(IOException ioe) {
    // Not logged
    Log.d("Broadcast", "Error sending inquiry.");
}

The getWifiBroadcastAddress() method is as seen here: https://lab.dyne.org/AndroidUDPBroadcast

Does anyone know why this would fail silently? Like I said my C# program running on another box is working just fine, doing the same thing, sending the same data every 5s, and WireShark sees those packets, but nothing from the Android phone.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

The following works for me, where I can broadcast a particular string value to a specified port (in your case Protocol.INQUIRY_PORT) on the other end(s), and all of the devices on the local subnet that are monitoring UDP on that port can recognize that string value, and accordingly can respond. I am broadcasting from the main thread, but listening for responses in an async task.

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);
    byte[] sendData = messageStr.getBytes();
    try {
        sendSocket = new DatagramSocket(null);
        sendSocket.setReuseAddress(true);
        //sendSocket.bind(new InetSocketAddress(Protocol.INQUIRY_PORT));
        sendSocket.setBroadcast(true);

        //Broadcast to all IP addresses on subnet
        try {
            DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, InetAddress.getByName("255.255.255.255"), Protocol.INQUIRY_PORT);
            sendSocket.send(sendPacket);
            System.out.println(getClass().getName() + ">>> Request packet sent to: 255.255.255.255 (DEFAULT)");
        } catch (Exception e) {
        }
    } catch (IOException e) {
        Log.e(TAG, "IOException: " + e.getMessage());
    }
}

Following is the corresponding UDP response listener code inside an async task class:

protected String doInBackground(String... params) {
        serverIP = "";
        try {
            //Keep a socket open to listen to all the UDP trafic that is destined for this port
            InetAddress myHostAddr = InetAddress.getByName("0.0.0.0");
            rcvSocket = new DatagramSocket(null);
            rcvSocket.setReuseAddress(true);
            rcvSocket.bind(new InetSocketAddress("0.0.0.0",Protocol.INQUIRY_PORT));
            rcvSocket.setBroadcast(true);

            while (true) {
                Log.i("VIS","Ready to receive broadcast packets!");
                //Receive a packet
                byte[] recvBuf = new byte[15000];
                DatagramPacket packet = new DatagramPacket(recvBuf, recvBuf.length);
                rcvSocket.receive(packet);
                //Packet received
                serverIP = packet.getAddress().getHostAddress();
                Log.i("VIS", "Packet received from: " + serverIP);
                String data = new String(packet.getData()).trim();
                Log.i("VIS", "Packet received; data: " + data);
                if (!data.equals("") && !data.equals(myInquiryString)) {
                    //break while loop and return IP address of server
                    break;
                }
            }
        } catch (IOException ex) {
            Log.i("VIS", "ServerDiscovery" + ex.getMessage());
        }
        return serverIP;
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...