Android MulticastSocket 组播

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android MulticastSocket 组播相关的知识,希望对你有一定的参考价值。

参考技术A MulticastSocket 发送组播消息,一些手机上可以发送、接收  组播 消息,有些手机不可用

     1>.能正常发送接收的手机,向组播地址发送了组播消息后,同时会向组播地址发送一个  IGMP v2的协议

2>.能发送,接收不到组播消息的手机设备,可以发现设备没有向组播地址发送IGMP协议

3>.而查看手机设备,在   /proc/net/   目录下,有igmp文件的设备会发送IGMP协议,能正常完成组播消息收发,而没有igmp文件的,就是不能完成组播消息收发的。igmp是IPv4下的协议文件,igmp6是IPv6的协议。可以看到所有设备都支持IPv6的igmp

4>.在android系统下,编译Linux kernel时有一config  CONFIG_IP_MULTICAST ,如果是定制系统在编译系统的时候配置这个选项   CONFIG_IP_MULTICAST=y  ,就能enable组播功能。但是有很多系统厂商在编译的时候都默认把这个config给disable了。

参考:

How can I know if IP Multicast is enabled

Android App用MulticastSocket监听组播,为什么连接到不

Many devices have multicast disabled in the kernel

Android:SSDP 卡在 MulticastSocket.receive()

【中文标题】Android:SSDP 卡在 MulticastSocket.receive()【英文标题】:Android: SSDP stuck on MulticastSocket.receive() 【发布时间】:2014-04-07 18:38:37 【问题描述】:

TL;DR: SSDP library 没有收到数据报。 Wireshark 显示预期的(?)流量。


我正在使用 android-dlna library 在 Android 应用中支持 SSDP。目标是发现支持 SSDP 的自定义设备,获取其 IP 地址,然后对其进行 RESTful API 调用。这在 iOS 上运行良好,但我在 Android 上接收数据报时遇到了一些问题。

使用 Wireshark,我可以确定 SSDP 搜索结束,设备返回 OK 状态,但此循环永远不会超过 receive() 方法:

SSDPSearchMsg search = new SSDPSearchMsg(SSDP.ST_ContentDirectory);
Log.e("SSDP", search.toString());

SSDPSocket sock = null;

try 
    sock = new SSDPSocket();
    sock.send(search.toString());

    while (true) 
        Log.e("SSDP", "Receive...");//only called once (stuck here)
        DatagramPacket dp = sock.receive();
        Log.e("SSDP", "Datagram Received with data " + new String(dp.getData()));
    
 catch (IOException e) 
    e.printStackTrace();

finally 
    Log.e("SSDP", "Closing Socket");
    if (sock != null)
        sock.close();

这一切都在AsyncTask 中完成。我看到以下打印到 logcat

SSDP    M-SEARCH * HTTP/1.1
SSDP    Host:239.255.255.250:1900
SSDP    Man:"ssdp:discover"
SSDP    ST:urn:schemas-upnp-org:service:ContentDirectory:1
SSDP    MX:3
SSDP    
SSDP    Receive...

Wireshark 报告以下相关数据报:

    Source      Destination    Protocol    Length    Info
---------------------------------------------------------------------------
 192.168.1.7  239.255.255.250    SSDP       175       M-SEARCH * HTTP/1.1
 192.168.1.1    192.168.1.7      SSDP       356       HTTP/1.1 200 OK

最后,我拥有以下清单权限:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />

我忽略了什么?为什么我没有收到响应数据报?

【问题讨论】:

我的代码和你的代码之间唯一的区别是我使用字节数组作为缓冲区而不是DatagramPacket dp = sock.receive();,并使用DatagramPacket dp = new DatagramPacket(buf, buf.length);。字节数组就是byte[] buf = new byte[1024];。然后我打电话给mSSDPSocket.receive(dp);,其中mSSDPSocket是我的MulticastSocket 【参考方案1】:

我知道这是一个老问题,但它也让我感到困惑,所以也许这会帮助其他偶然发现这个问题的人。如果您没有获取到MulticastLock,Android 会过滤掉多播数据包,因此更新代码以获取MulticastLock 并在完成后释放它。

final WifiManager wifi = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
WifiManager.MulticastLock lock = wifi.createMulticastLock("ssdp");
try 
    lock.acquire();
    sock = new SSDPSocket();
    sock.send(search.toString());

    while (true) 
        Log.e("SSDP", "Receive...");//only called once (stuck here)
        DatagramPacket dp = sock.receive();
        Log.e("SSDP", "Datagram Received with data " + new String(dp.getData()));
    
 catch (IOException e) 
    e.printStackTrace();
 finally 
    Log.e("SSDP", "Closing Socket");
    if (sock != null)
        sock.close();
    if(lock.isHeld()) 
        lock.release();
    

需要以下权限(已经在 OP 的清单文件中)--

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

【讨论】:

以上是关于Android MulticastSocket 组播的主要内容,如果未能解决你的问题,请参考以下文章

Android:SSDP 卡在 MulticastSocket.receive()

Android 局域网内功能模块开发,教你怎么快速获取局域网内所有IP并且进行通信------ MulticastSocket

Java 网络编程:(十三)案例四:使用 MulticastSocket 实现多点广播

Android 投屏 发现

java与网络(IPv4组播)

(四)Android基于UDP的多客户端语音通信