Как использовать многоадресную передачу в многодомной системе (Java, Linux)

Это в Java, но я всегда могу вернуться к C через JNI, если это необходимо.

У меня есть система с двумя сетевыми картами, каждая из которых подключена к отдельной подсети. Я хочу использовать многоадресную передачу (в частности, SDP) для обнаружения других хостов в обеих сетях.

Одна сеть проста: создайте MulticastSocket на указанном порту, присоединитесь к нему, и я получу пакеты. Простота.

Две сети: пока невозможно. Я пробовал:

1) создание двух сокетов, привязка к одному и тому же порту и использование setInterface() или setNetworkInterface() для "подключения" к нужному интерфейсу. Не повезло, даже после различных перестановок setReuseAddress ().

2) создать один сокет, а затем попытаться присоединиться дважды, с двумя вызовами joinGroup(SocketAddress mcastaddr, NetworkInterface netIf). Второй вызов присоединения не проходит.

Решения за пределами Java были бы отличными. В частности, если бы я мог настроить многоадресные маршруты, которые бы эффективно "объединяли" два интерфейса (я мог бы тогда посмотреть на каждый пакет, чтобы определить, какая сеть), что было бы хорошо. Как я упоминал ранее, любое количество нативного кода можно использовать в этой среде (Linux с Java-инфраструктурой Apache "luni").

Спасибо!

4 ответа

По совпадению я недавно работал над подобной проблемой.

Вот некоторый 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);
    }
}

Я бы порекомендовал использовать JGroups, который абстрагирует все, что вы пытаетесь сделать, если я правильно понимаю ваши потребности. Это элегантный и хорошо сделанный фреймворк для многоадресной передачи (и семантики, подобной многоадресной, эмулируемой при необходимости).

Рассматривали ли вы использовать ZeroConf для этого?

Проект jmdns имеет чистую реализацию Java, которая должна работать очень хорошо.

У меня нет разумной настройки, чтобы попробовать это здесь, но получение многоадресных сообщений не должно требовать привязки MulticastSocket к номеру порта из адреса многоадресной рассылки, а setNetworkInterface используется для установки интерфейса, используемого для исходящих сообщений.

Что бы я попытался создать две разные MulticastSockets (на любом свободном порту), а затем использовать joinGroup(SocketAddress mcastaddr, NetworkInterface netIf) для каждого из них, используя один и тот же адрес многоадресной рассылки, но разные сетевые интерфейсы.

Другие вопросы по тегам