通过Wi-Fi Direct进行广播

15

我正在考虑在多个Android设备之间通过Wi-Fi Direct连接进行广播的可能性。我创建了一个简单的消息广播应用程序来测试它是否可行,但到目前为止,我还无法广播消息。当我尝试发送数据包时,我收到了一个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);
}

这篇文章 提到使用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();
}

我也尝试了向DatagramSocket添加通配符地址,方法是将InetAddress.getByName("0.0.0.0")作为参数添加,但没有成功。

有什么建议吗?


顺便说一句:看看这篇文章:http://developer.android.com/training/connect-devices-wirelessly/wifi-direct.html - Grim
1个回答

12

抱歉,这段内容已被无耻地从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);

请记住,你需要以下权限才能让它工作:
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE"/>


3
使用该函数获取广播地址后,SocketException异常消失了,并且广播似乎可以正常工作,但我在第二个设备上接收广播时遇到问题。我以同样的方式在接收设备上初始化了一个DatagramSocket。我还尝试在接收的DatagramSocket上使用通配符地址,通过将InetAddress.getByName("0.0.0.0")添加为参数。但是没有成功。 - KatoStoelen
@user2190832 给我的回答添加了更多细节,以读取UDP。 - Romain Hippeau
代码运行得很好,谢谢!关于设备的一些细节:我基于这个代码构建了自己的库来处理通信。我目前使用的是端口8888。我的Nexus 5可以发送和接收。我的Moto G只能发送数据包(并接收自己的数据包,但不能接收其他设备的数据包)。最近我在三星Galaxy S2上尝试了一下,可以发送和接收数据包。不知何故,摩托罗拉阻止了传入的广播。我在两个不同的Moto G上尝试过,一个是具有特定防火墙策略的rooted版本,另一个是原版,但都没有成功。 - Rudolf Real
这对我也不起作用,只有群组所有者能够接收广播数据包,但客户端不能,两台设备都是三星(C5和C7)。 - Amos

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接