1

I have a python3.7 server as follows:

#! /usr/bin/python3.7

MYPORT = 5000
MYGROUP_4 = '224.5.6.7'
MYTTL = 1 # Increase to reach other networks

import time
import struct
import socket
import sys

def main():
    group = MYGROUP_4
    receiver(group)

def receiver(group):
    addrinfo = socket.getaddrinfo(group, None)[0]
    s = socket.socket(addrinfo[0], socket.SOCK_DGRAM)
    s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    s.bind(('', MYPORT))

    group_bin = socket.inet_pton(addrinfo[0], addrinfo[4][0])
    mreq = group_bin + struct.pack('=I', socket.INADDR_ANY)
    s.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)

    while True:
        data, sender = s.recvfrom(1500)
        while data[-1:] == '\0': data = data[:-1] # Strip trailing \0's
        s.sendto(str.encode("ack"), sender)
        print(str(sender) + '  ' + repr(data))


if __name__ == '__main__':
    main()

and a Java 16 client as follows:

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.MulticastSocket;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.StandardSocketOptions;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

public class MulticastServer {
    private static final String ipAddress = "224.5.6.7";
    private static final int port = 5000;
    private static final String msg = "openhab-PiBridge";

    private static void send(MulticastSocket s, InetAddress group, int port, String msg) throws IOException{
        byte[] msgBytes = msg.getBytes();
        DatagramPacket p = new DatagramPacket(msgBytes, msgBytes.length, group, port);
        s.send(p);
    }

    private static boolean isLocalAddress(InetAddress inetAddress) {
        try {
            List<String> localAddresses = Collections
                    .list(NetworkInterface.getNetworkInterfaces())
                    .stream()
                        .flatMap(ni -> ni.inetAddresses())
                        .map(ia->ia.getHostAddress())
                        .collect(Collectors.toList());
            boolean isLocal = localAddresses.contains(inetAddress.getHostAddress());
            return isLocal;
        } catch (SocketException e) {
            return false;
        }
    }

    private static String receive(MulticastSocket s) throws IOException {
        byte[] buf = new byte[1500];
        DatagramPacket recv = new DatagramPacket(buf, buf.length);
        s.receive(recv);
        while(isLocalAddress(recv.getAddress())) {
            for(int i = 0; i < recv.getLength(); i++)
                buf[i] = 0;
            s.receive(recv);
        }
        String data = new String(recv.getData());
        return data;
    }
    
    public static void main(String args[]) throws Exception {
        InetAddress group = InetAddress.getByName(ipAddress);
        NetworkInterface networkInterface = NetworkInterface.getByInetAddress(group);
        InetSocketAddress sockAddr = new InetSocketAddress(group, port);
        try (MulticastSocket s = new MulticastSocket(port)) {
            s.setOption(StandardSocketOptions.IP_MULTICAST_LOOP, false);
            s.joinGroup(sockAddr, networkInterface);
            send(s, group, port, msg);
            String data = receive(s);
            s.leaveGroup(sockAddr, networkInterface);
            System.out.println(data);
        }
    }
}

Output from the client is:

openhab-PiBridge

which is what was sent by the client, however, the server sent "ack". I have run tcpdump on the client host and it shows 16 bytes sent and 3 bytes received. Which is correct. Why does my Java receive routine return the same data that was sent. Also, how do I get the IP address of the server? recv.getAddress() returns null and recv.getSocketAddress() returns the address of the client.

Update:

I've solved the problem by checking to see if the received packet came from a local address (see isLocalAddress). For some reason I couldn't get the s.setOption(StandardSocketOptions.IP_MULTICAST_LOOP, false) call to act as I had hoped on MacOS Big Sur. If the packet comes from a local address, I had to clear the buffer and reissue the recv. All works fine now.

So, the question about getting the wrong address isn't really an issue. That was due to the fact that the packet with the local address was really coming from a local address.

I'd appreciate if any one would enlighten me as to why IP_MULTICAST_LOOP isn't working in this case.

AixNPanes
  • 1,170
  • 3
  • 14
  • 33
  • *Also, how do I get the IP address of the server* - what is `String ipAddress = "224.5.6.7"` ? – Scary Wombat Oct 06 '21 at 01:06
  • Did you follow the javadocs for https://docs.oracle.com/javase/7/docs/api/java/net/MulticastSocket.html? Why not use https://docs.oracle.com/javase/7/docs/api/java/net/MulticastSocket.html#joinGroup(java.net.InetAddress) ? – Scary Wombat Oct 06 '21 at 01:11
  • This is caused by multicast loopback, which you can turn off with the API. – user207421 Oct 06 '21 at 01:26
  • Scary Wombat - 224.0.0.0-255.255.255.255 are specified by IANA as in the Multicast address range. Perhaps I should have picked something in 224.0 rather than 224.5 as 224.0 is in the Local Network Control Block where 224.5 is reserver, but I shouldn't think that should make I difference on a local network. – AixNPanes Oct 07 '21 at 18:26
  • Scary Wombat - I think I did follow the first link. I did NOT follow the second link as that doc is for Java7 I'm using Java16 and that form of call is deprecated. – AixNPanes Oct 07 '21 at 18:27
  • user207421 - doesn't s.setOption(StandardSocketOptions.IP_MULTICAST_LOOP, false); so that? – AixNPanes Oct 07 '21 at 18:29
  • See update for workaround. – AixNPanes Oct 09 '21 at 20:58

0 Answers0