12

I am developing a chat application where Android clients will exchange their IP's using multicasting(UDP).

Every device will send its ip to multiple clients(all the devices running this app) in one separate Thread. There will be another receiver thread which will listen to these multicast packets. Here is my code.

//Multicasting code.

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

//Receiver code

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

The problem is every device prints its own address. It seems it never listens to other multicast packages(I mean it should print other ip's as well). I also get a below log, not sure if that's related.

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

Any help will be appreciated.

Shashank Kadne
  • 7,993
  • 6
  • 41
  • 54

2 Answers2

15

You need acquire a MulticastLock in your app, which will allow your app receive packets that are not explicitly addressed to this device on the network.

Permission required:

<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"/>

Sample code:

// 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;
}
yorkw
  • 40,926
  • 10
  • 117
  • 130
  • It looks like this is only for wifi multicast packets. I am multicasting over internet(using normal APN, no WIFI). Will it still work? – Shashank Kadne Nov 05 '12 at 06:27
  • I don't think it is possible on Android, see if answer [here](http://stackoverflow.com/questions/3068497/udp-multicast-over-the-internet) helps. – yorkw Nov 05 '12 at 09:28
  • @ShashankKadne, I reviewed one of my project recently, which use JmDNS for some multicast operation. The demo version self-publish a mock mdns service and detect it on the device. I actually forget I use to test and run it many times under 3G network. I just double checked the behaviour and I can confirm now `WifiManager.MulticastLock` works under 3G network (regardless of whether WIFI is turned on/off, with 3G being active in the status bar). Please try it and let me know if this works on your end too. – yorkw Nov 06 '12 at 22:26
  • As you can see, my demo app create and detect the mock mdns service by itself in the same network (regardless of 3G or WIFI). In you case, if the mdns packets (says raised from another network) is reachable in your phone's network (may need some routing), it should work as expected. – yorkw Nov 06 '12 at 22:32
  • (+1)Thanks @yorkw.I will try and let you know. – Shashank Kadne Nov 07 '12 at 06:32
  • I use native BSD sockets to broadcast to INADDR_BROADCAST on a IPv4 LAN and never needed to use `MulticastLock`. However, since Android 12 I now find that I need to this (on Android 12 Beta 4 at least). – Columbo Sep 08 '21 at 10:50
6

IPv4 multicast support in android is poorely implemented. There are bugs from cupcake era still present.

I ran into a similar problem I was doing a project that relied on mDNS/multicast for service discovery. My Android app would simply not subscribe to the multicast group. I verified this by creating a portable access point on a Ubuntu 14.04 machine and running tcpdump on it. Android devices connected to it simply didn't emit IGMP messages required for joining a group. I could send packets but not receive them.

What I noticed that I was getting an IPv6 join group message to all-systems whenever I joined the networked. This prompted me to try a IPv6 multicast address and that worked.

Newer android devices support IPv6, which has built-in and mandatory multicast support. So instead of using an Class 4 IPv4 multicast address, modify your code to use an IPv6 address. This will make your code to work on at least the local level.

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

This page has a wealth of information about which IP to use as per your needs.

Some say that it works without the WiFiManager.crrateMulticastLock() but I didn't try that.

Multicasting to global networks is certainly possible theoretically. But I've never seen a successful practical implementation of one. Given the esoteric routers and firewalls that exist all around.

This SO question shows how it is done on desktop. Similar code also works with android.

IPv6 Multicast example

Community
  • 1
  • 1
recrsn
  • 450
  • 5
  • 12