Android静默发送udp广播失败Android、udp

2023-09-07 12:46:32 作者:流光若逝丶情若殇

我想通过使用网络的广播地址来实现服务发现.我正在使用 WireShark 嗅探数据包,以确认我的 UDP 数据包没有被发送.网络代码未在 UI 线程上运行.DatagramSocket.send 调用返回,没有抛出异常,但是包括 WireShark 在内的其他程序看不到任何异常.我已经验证了getWifiBroadcastAddress返回的地址实际上是我网络的广播地址.

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.

我已经通过编写 C# 程序验证网络支持广播,在另一台机器上运行,并且 WireShark正在检测来自该程序的广播数据包.

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.

这是我的 Android Java 代码:

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

getWifiBroadcastAddress() 方法如下所示:https://lab.dyne.org/AndroidUDPBroadcast

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

有谁知道为什么这会默默地失败?就像我说的,我在另一个机器上运行的 C# 程序运行良好,做同样的事情,每 5 秒发送一次相同的数据,WireShark 看到这些数据包,但 Android 手机没有.

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.

推荐答案

以下对我有用,我可以将特定的字符串值广播到另一端的指定端口(在你的情况下为 Protocol.INQUIRY_PORT),并且本地子网上所有在该端口上监视 UDP 的设备都可以识别该字符串值,并相应地做出响应.我从主线程广播,但在异步任务中监听响应.

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

以下是异步任务类中对应的 UDP 响应侦听器代码:

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;
}
 
精彩推荐
图片推荐