如何在多宿主系统(Java、Linux)上使用多播

如何在多宿主系统(Java、Linux)上使用多播,java,multicast,multihomed,Java,Multicast,Multihomed,这是用Java编写的,但如果需要,我可以通过JNI随时恢复到C 我有一个带有两个NIC的系统,每个NIC连接到不同的子网。我想使用多播(特别是SDP)来发现两个网络上的其他主机 一个网络很简单:在指定的端口上创建一个多播套接字,对它进行joinGroup,然后我就可以得到数据包。简单 两个网络:目前不可能。我试过: 1) 创建两个套接字,绑定到同一端口,并使用setInterface()或setNetworkInterface()来“连接”到正确的接口。即使在对setReuseAddress()

这是用Java编写的,但如果需要,我可以通过JNI随时恢复到C

我有一个带有两个NIC的系统,每个NIC连接到不同的子网。我想使用多播(特别是SDP)来发现两个网络上的其他主机

一个网络很简单:在指定的端口上创建一个多播套接字,对它进行joinGroup,然后我就可以得到数据包。简单

两个网络:目前不可能。我试过:

1) 创建两个套接字,绑定到同一端口,并使用setInterface()或setNetworkInterface()来“连接”到正确的接口。即使在对setReuseAddress()进行了各种排列之后,也没有运气

2) 创建一个套接字,然后尝试加入两次,并调用两次joinGroup(SocketAddress mcastaddr,NetworkInterface netIf)。第二个join调用失败

Java之外的解决方案将非常好。特别是,如果我可以设置多播路由,有效地“组合”两个接口(然后我可以查看每个数据包以确定哪个网络),那就好了。正如我前面提到的,任何数量的本机代码都可以在这个环境中使用(Linux,使用Apache“luni”java基础设施)


谢谢

我没有合理的设置来尝试此操作,但是接收多播消息不需要将多播套接字绑定到来自多播地址的端口号,并且setNetworkInterface用于设置用于出站消息的接口


我会尝试创建两个不同的多播套接字(在任何空闲端口上),然后使用joinGroup(SocketAddress mcastaddr,NetworkInterface netIf)在每个套接字上使用相同的多播地址,但不同的网络接口。

您考虑过使用ZeroConf吗

/**
 * Demonstrate multi-homed multicast listening
 *
 * usage: java Multihome eth0 eth1 lo <etc>
 */

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.util.Enumeration;
import java.util.HashSet;
import java.util.Set;

public class Multihome {
    // SDP constants
    public static final String MULTICAST_ADDRESS = "239.255.255.250";
    public static final int MULTICAST_PORT = 1900;

    // args: each arg is the name of an interface.
    public void doMain(Set<String> args)
            throws Exception
    {
        InetSocketAddress socketAddress =
                new InetSocketAddress(MULTICAST_ADDRESS, MULTICAST_PORT);
        MulticastSocket socket = new MulticastSocket(MULTICAST_PORT);
        Enumeration<NetworkInterface> ifs =
                NetworkInterface.getNetworkInterfaces();

        while (ifs.hasMoreElements()) {
            NetworkInterface xface = ifs.nextElement();
            Enumeration<InetAddress> addrs = xface.getInetAddresses();
            String name = xface.getName();

            while (addrs.hasMoreElements()) {
                InetAddress addr = addrs.nextElement();

                System.out.println(name + " ... has addr " + addr);
            }

            if (args.contains(name)) {
                System.out.println("Adding " + name + " to our interface set");
                socket.joinGroup(socketAddress, xface);
            }
        }

        byte[] buffer = new byte[1500];
        DatagramPacket packet = new DatagramPacket(buffer, buffer.length);

        while (true) {
            try {
                packet.setData(buffer, 0, buffer.length);
                socket.receive(packet);
                System.out.println("Received pkt from " + packet.getAddress() +
                                   " of length " + packet.getLength());
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
    }

    public static void main(String[] args)
            throws Exception
    {
        Set<String> argSet = new HashSet<String>();
        Multihome multi = new Multihome();

        for (String arg : args) {
            argSet.add(arg);
        }

        multi.doMain(argSet);
    }
}

jmdns项目有一个纯java实现,应该可以很好地工作

如果我正确理解您的需求,我建议使用它,它将您试图做的一切抽象化。这是一个优雅且制作良好的多播框架(以及类似多播的语义,在必要时进行仿真)。

巧合的是,我最近正在研究一个类似的问题

下面是一些Java代码,它实现了您想要的功能——它在几个接口上拾取SDP数据包。joinGroup用于“附加”到指定的接口

/**
 * Demonstrate multi-homed multicast listening
 *
 * usage: java Multihome eth0 eth1 lo <etc>
 */

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.util.Enumeration;
import java.util.HashSet;
import java.util.Set;

public class Multihome {
    // SDP constants
    public static final String MULTICAST_ADDRESS = "239.255.255.250";
    public static final int MULTICAST_PORT = 1900;

    // args: each arg is the name of an interface.
    public void doMain(Set<String> args)
            throws Exception
    {
        InetSocketAddress socketAddress =
                new InetSocketAddress(MULTICAST_ADDRESS, MULTICAST_PORT);
        MulticastSocket socket = new MulticastSocket(MULTICAST_PORT);
        Enumeration<NetworkInterface> ifs =
                NetworkInterface.getNetworkInterfaces();

        while (ifs.hasMoreElements()) {
            NetworkInterface xface = ifs.nextElement();
            Enumeration<InetAddress> addrs = xface.getInetAddresses();
            String name = xface.getName();

            while (addrs.hasMoreElements()) {
                InetAddress addr = addrs.nextElement();

                System.out.println(name + " ... has addr " + addr);
            }

            if (args.contains(name)) {
                System.out.println("Adding " + name + " to our interface set");
                socket.joinGroup(socketAddress, xface);
            }
        }

        byte[] buffer = new byte[1500];
        DatagramPacket packet = new DatagramPacket(buffer, buffer.length);

        while (true) {
            try {
                packet.setData(buffer, 0, buffer.length);
                socket.receive(packet);
                System.out.println("Received pkt from " + packet.getAddress() +
                                   " of length " + packet.getLength());
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
    }

    public static void main(String[] args)
            throws Exception
    {
        Set<String> argSet = new HashSet<String>();
        Multihome multi = new Multihome();

        for (String arg : args) {
            argSet.add(arg);
        }

        multi.doMain(argSet);
    }
}
/**
*演示多宿主多播侦听
*
*用法:java多址eth0 eth1 lo
*/
导入java.io.IOException;
导入java.net.DatagramPacket;
导入java.net.InetAddress;
导入java.net.InetSocketAddress;
导入java.net.MulticastSocket;
导入java.net.NetworkInterface;
导入java.net.SocketException;
导入java.util.Enumeration;
导入java.util.HashSet;
导入java.util.Set;
公共类多家庭{
//SDP常数
公共静态最终字符串多播_ADDRESS=“239.255.255.250”;
公共静态最终int多播_端口=1900;
//args:每个arg都是接口的名称。
公共无效域(设置参数)
抛出异常
{
InetSocketAddress socketAddress=
新的InetSocketAddress(多播地址、多播端口);
MulticastSocket=新的MulticastSocket(多播_端口);
枚举ifs=
NetworkInterface.getNetworkInterfaces();
while(ifs.hasMoreElements()){
NetworkInterface xface=ifs.nextElement();
枚举地址=xface.getInetAddresses();
String name=xface.getName();
while(addrs.hasMoreElements()){
InetAddress addr=addrs.nextElement();
System.out.println(name+“…有addr”+addr);
}
如果(参数包含(名称)){
System.out.println(“将“+name+”添加到我们的接口集”);
socket.joinGroup(socketAddress,xface);
}
}
字节[]缓冲区=新字节[1500];
DatagramPacket数据包=新的DatagramPacket(buffer,buffer.length);
while(true){
试一试{
packet.setData(buffer,0,buffer.length);
套接字接收(数据包);
System.out.println(“从“+packet.getAddress()接收到pkt”)+
“of length”+packet.getLength());
}捕获(IOEX异常){
例如printStackTrace();
}
}
}
公共静态void main(字符串[]args)
抛出异常
{
Set argSet=new HashSet();
Multihome multi=新的Multihome();
for(字符串arg:args){
argSet.add(arg);
}
多域(argSet);
}
}

拯救了我的一天!在使用java networking api进行了徒劳的尝试之后,这个库似乎非常适合我的需要。多播数据包将在发送的数据包中指定的端口上转发到您的NIC,因此,如果您没有绑定到同一端口,您将不会收到它。因此,您必须绑定该端口才能接收多播数据包。我已经试过了。。。