Android设备无法接收多播包。

12

我正在开发一款聊天应用程序,其中安卓客户端将使用多播(UDP)交换它们的IP地址。

每个设备都将在一个单独的线程中向多个客户端(运行此应用程序的所有设备)发送其IP地址。将会有另一个接收器线程来监听这些多播数据包。以下是我的代码。

//多播代码。

DatagramSocket socket = new DatagramSocket(9898);
            byte buff[] = ip.getBytes();
            DatagramPacket packet = new DatagramPacket(buff, buff.length, InetAddress.getByName("224.0.0.1"),9999);
            socket.send(packet);
            socket.close();

//接收器代码

MulticastSocket socket = new MulticastSocket(9999);
        InetAddress group = InetAddress.getByName("224.0.0.1");
        socket.joinGroup(group);

        DatagramPacket packet;

            byte[] buf = new byte[256];
            byte  b = 'x'; //just a separator for time being
            Arrays.fill(buf,b);
            packet = new DatagramPacket(buf, buf.length);
            String received= "";
            while(received!=null)
            {
                socket.receive(packet);
                received = new String(packet.getData());
                received = received.substring(0,received.indexOf('x'));
                this.setIp(received);
                System.out.println("Address: " + received);
            }

        socket.leaveGroup(group);
        socket.close();

问题在于每个设备都打印自己的地址。似乎它从不侦听其他组播包(我是说它应该打印其他IP地址)。我还收到了下面的日志,不确定它是否相关。

11-04 23:56:17.985: I/OSNetworkSystem(603): mcastAddDropMembership interfaceIndex=0

任何帮助都将不胜感激。

2个回答

15

您的应用需要获取MulticastLock,这将允许您的应用在网络上接收未明确寻址到此设备的数据包。

所需权限:

<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

示例代码:

// Acquire multicast lock
WifiManager wifi = (WifiManager) getSystemService(Context.WIFI_SERVICE);
MulticastLock multicastLock = wifi.createMulticastLock("multicastLock");
multicastLock.setReferenceCounted(true);
multicastLock.acquire();

//Do some mutlicast job here
... ...

// Once your finish using it, release multicast lock
if (multicastLock != null) {
    multicastLock.release();
    multicastLock = null;
}

看起来这只适用于WiFi组播数据包。我正在互联网上进行组播(使用普通APN,没有WiFi)。它仍然有效吗? - Shashank Kadne
我认为在Android上不可能实现,看看这里的答案是否有帮助:https://dev59.com/r3A75IYBdhLWcg3w3M9e。 - yorkw
@ShashankKadne,我最近回顾了我的一个项目,其中使用了JmDNS进行一些多播操作。演示版本自行发布模拟mdns服务并在设备上检测它。我实际上忘记了我曾经在3G网络下测试和运行它很多次。我刚刚仔细检查了行为,现在可以确认WifiManager.MulticastLock在3G网络下工作(无论WIFI是否打开/关闭,在状态栏中激活3G)。请尝试一下,让我知道这在你那边是否有效。 - yorkw
正如您所看到的,我的演示应用程序可以在同一网络中自行创建和检测模拟mdns服务(无论是3G还是WIFI)。在您的情况下,如果mdns数据包(可能来自另一个网络)可以在您手机的网络中到达(可能需要一些路由),则它应该按预期工作。 - yorkw
谢谢@yorkw。我会尝试并告诉你结果。 - Shashank Kadne
我使用本机BSD套接字来广播到IPv4 LAN上的INADDR_BROADCAST,并且从未需要使用MulticastLock。然而,由于Android 12,我现在发现我至少需要这样做(在Android 12 Beta 4上)。 - Columbo

6
Android中的IPv4多播支持实现非常差。从杯子蛋糕时代开始仍然存在着bug。
我遇到了类似的问题,当时我在做一个依赖于mDNS /多播进行服务发现的项目。我的Android应用程序根本不会订阅多播组。我通过在Ubuntu 14.04机器上创建一个便携式接入点并在其上运行tcpdump来验证了这一点。连接到它的Android设备根本不会发出加入组所需的IGMP消息。我可以发送数据包但无法接收它们。
我注意到每当我加入网络时,我都会收到一个IPv6加入组消息到所有系统。这促使我尝试使用IPv6多播地址,那样就行了。
较新的Android设备支持IPv6,其中内置且强制执行多播支持。因此,不要使用Class 4 IPv4多播地址,而是修改您的代码以使用IPv6地址。这将使您的代码至少在本地级别上工作。

http://developer.android.com/reference/java/net/Inet6Address.html

这个页面包含大量关于如何根据需要使用哪个IP的信息。
有些人说它可以在没有WiFiManager.crrateMulticastLock()的情况下工作,但我没有尝试过。
理论上,向全球网络进行多播是完全可能的。但我从未见过一个成功的实际实现,考虑到存在各种奇特的路由器和防火墙。
这个SO问题展示了在桌面上如何完成它。类似的代码也适用于Android。 IPv6多播示例

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