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.