【问题标题】:Broadcasting over Wi-Fi Direct通过 Wi-Fi Direct 广播
【发布时间】:2013-03-09 14:37:12
【问题描述】:

我正在研究通过 Wi-Fi Direct 连接在多个 Android 设备之间进行广播的可能性。我创建了一个简单的消息广播应用程序来测试它是否有效,但到目前为止我还无法广播消息。当我尝试发送数据包时,我收到 SocketException(网络无法访问):

03-20 13:23:00.148: E/UdpBroadcaster(4180): sendto failed: ENETUNREACH (Network is unreachable)
03-20 13:23:00.148: E/UdpBroadcaster(4180): java.net.SocketException: sendto failed: ENETUNREACH (Network is unreachable)
03-20 13:23:00.148: E/UdpBroadcaster(4180):     at libcore.io.IoBridge.maybeThrowAfterSendto(IoBridge.java:496)
03-20 13:23:00.148: E/UdpBroadcaster(4180):     at libcore.io.IoBridge.sendto(IoBridge.java:465)
03-20 13:23:00.148: E/UdpBroadcaster(4180):     at java.net.PlainDatagramSocketImpl.send(PlainDatagramSocketImpl.java:182)
03-20 13:23:00.148: E/UdpBroadcaster(4180):     at java.net.DatagramSocket.send(DatagramSocket.java:307)
03-20 13:23:00.148: E/UdpBroadcaster(4180):     at com.example.android.wifidirect.UdpBroadcaster.sendMessage(UdpBroadcaster.java:59)
03-20 13:23:00.148: E/UdpBroadcaster(4180):     at com.example.android.wifidirect.UdpBroadcaster.run(UdpBroadcaster.java:44)
03-20 13:23:00.148: E/UdpBroadcaster(4180): Caused by: libcore.io.ErrnoException: sendto failed: ENETUNREACH (Network is unreachable)
03-20 13:23:00.148: E/UdpBroadcaster(4180):     at libcore.io.Posix.sendtoBytes(Native Method)
03-20 13:23:00.148: E/UdpBroadcaster(4180):     at libcore.io.Posix.sendto(Posix.java:146)
03-20 13:23:00.148: E/UdpBroadcaster(4180):     at libcore.io.BlockGuardOs.sendto(BlockGuardOs.java:177)
03-20 13:23:00.148: E/UdpBroadcaster(4180):     at libcore.io.IoBridge.sendto(IoBridge.java:463)
03-20 13:23:00.148: E/UdpBroadcaster(4180):     ... 4 more

这是我的代码的精髓:

InetAddress broadcastAddress = InetAddress.getByName("255.255.255.255");
int port = 8888;

DatagramSocket socket = new DatagramSocket(port);
socket.setBroadcast(true);
socket.connect(broadcastAddress, port);

String message = "Hello";
byte[] buffer = message.getBytes();

DatagramPacket packet = new DatagramPacket(
        buffer, buffer.length, broadcastAddress, port);

try {
    socket.send(packet); // <----- Causes a SocketException
} catch (IOException e) {
    Log.e(TAG, e.getMessage(), e);
}

This post 建议应该可以通过 Wi-Fi Direct 进行广播。

有谁知道在 Android 设备上通过 Wi-Fi Direct 进行广播是否真的有效?如果它应该工作,我做错了什么?

我开始认为设备不知道将广播数据包路由到哪里。在我的情况下,它需要在无需 root 设备并手动添加广播数据包路由的情况下工作。


更新

使用 Romain Hippeau 建议的getBroadcastAddress() 函数后,SocketException 消失了,看起来广播正在按预期工作。但是,我在第二台设备上接收广播时遇到问题。

我正在使用以下代码来接收广播:

DatagramSocket socket = null;
try {
    socket = new DatagramSocket(8888);
    socket.setBroadcast(true); // Not needed?
    socket.setSoTimeout(200);

    DatagramPacket packet = null;
    while (!mStopping) {
        byte[] buffer = new byte[1024];
        packet = new DatagramPacket(buffer, buffer.length);

        try {
            socket.receive(packet);

            if (packet.getData().length > 0) {
                String receivedString = new String(packet.getData());

                Log.i(TAG, "Received string: " + receivedString);
            }
        } catch (InterruptedIOException e) { /* Ignore */ }
    }
} catch (IOException e) {
    Log.e(TAG, e.getMessage(), e);
} finally {
    if (socket != null)
        socket.close();
}

我还尝试通过将InetAddress.getByName("0.0.0.0") 添加为参数,将通配符地址添加到DatagramSocket,但没有成功。

建议?

【问题讨论】:

标签: java android broadcast socketexception wifi-direct


【解决方案1】:

无耻地盗取https://code.google.com/p/boxeeremote/wiki/AndroidUDP

尝试通过这种方式获得网络连接:

InetAddress getBroadcastAddress() throws IOException {
    WifiManager wifi = 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);
}  

然后尝试这样发送数据包:

DatagramSocket socket = new DatagramSocket(PORT);
socket.setBroadcast(true);
DatagramPacket packet = new DatagramPacket(data.getBytes(), data.length(),
    getBroadcastAddress(), PORT);
socket.send(packet);

// If you want to listen for a response ...
byte[] buf = new byte[1024];
DatagramPacket packet = new DatagramPacket(buf, buf.length);
socket.receive(packet);

编辑:从同一页面阅读试试这个......

WifiManager wifi = (WifiManager) this.getSystemService(Context.WIFI_SERVICE);
MulticastLock lock = wifi.createMulticastLock("dk.aboaya.pingpong");
lock.acquire();
serverSocket = new DatagramSocket(19876);
serverSocket.setSoTimeout(15000); //15 sec wait for the client to connect
byte[] data = new byte[UDPBatPositionUpdater.secretWord.length()]; 
DatagramPacket packet = new DatagramPacket(data, data.length);
serverSocket.receive(packet);
lock.release();
String s = new String(packet.getData());
System.out.println(s);

请记住,您需要以下权限才能使其工作:

【讨论】:

  • 使用该函数获取广播地址后,SocketException 消失了,广播似乎工作,但我在第二个设备上接收广播时遇到问题。我在接收设备上以相同的方式初始化DatagramSocket。我还尝试通过添加InetAddress.getByName("0.0.0.0") 作为参数在接收DatagramSocket 上使用通配符地址。没有运气。
  • @user2190832 为我阅读 UDP 的答案添加了更多细节。
  • 代码效果很好,谢谢!关于设备的一些细节:我构建了自己的库来处理基于此代码的通信。我目前正在使用端口 8888。我的 Nexus 5 可以发送和接收。我的 Moto G 只能发送包裹(并接收自己的包裹,但不能从其他设备接收)。我最近试用了三星 Galaxy S2,可以发送和接收包裹。摩托罗拉以某种方式阻止了传入的广播。我尝试了两种不同的 Moto G,一种因特定的防火墙策略而腐烂,另一种是库存,但没有运气。