Рубрики
Без рубрики

Широковещательная и многоадресная передача на Java

Узнайте, как можно обрабатывать связь “один ко всем” (широковещательная передача) и “один ко многим” (многоадресная передача) в Java.

Автор оригинала: Deep Jain.

1. введение

В этой статье мы опишем, как можно обрабатывать связь “один ко всем” (широковещательная передача) и “один ко многим” (многоадресная передача) в Java. Концепции широковещательной и многоадресной рассылки, описанные в этой статье, основаны на протоколе UDP.

Мы начнем с краткого обзора дейтаграмм и широковещания, а также того, как это реализовано в Java. Мы также рассматриваем недостатки вещания и предлагаем многоадресную передачу в качестве альтернативы вещанию.

Наконец, в заключение мы обсудим поддержку этих двух методов адресации как в IPv4, так и в IPv6 .

2. Краткое изложение дейтаграммы

Согласно официальному определению дейтаграммы, “Дейтаграмма-это независимое, автономное сообщение, отправленное по сети, прибытие, время прибытия и содержание которого не гарантируется”.

В Java/| java.net пакет предоставляет классы DatagramPacket и DatagramSocket , которые могут использоваться для связи по протоколу UDP. UDP обычно используется в сценариях, где более низкая задержка важнее гарантированной доставки, таких как потоковая передача аудио/видео, обнаружение сети и т. Д.

Чтобы узнать больше об UDP и дейтаграммах в Java, обратитесь к Руководству по UDP в Java .

3. Вещание

Широковещательная передача-это тип связи “один ко всем”, то есть намерение состоит в том, чтобы отправить дейтаграмму всем узлам сети. В отличие от связи “точка-точка”, нам не нужно знать IP-адрес целевого хоста . Вместо этого используется широковещательный адрес.

Согласно протоколу IPv4, широковещательный адрес-это логический адрес, по которому устройства, подключенные к сети, могут принимать пакеты. В нашем примере мы используем определенный IP-адрес, 255.255.255.255 , который является широковещательным адресом локальной сети.

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

Во-первых, мы покажем, как транслировать сообщение. В этом случае нам нужно вызвать метод set Broadcast() в сокете, чтобы сообщить ему, что пакет должен быть передан:

public class BroadcastingClient {
    private static DatagramSocket socket = null;

    public static void main((String[] args)) throws IOException {
        broadcast("Hello", InetAddress.getByName("255.255.255.255"));
    }

    public static void broadcast(
      String broadcastMessage, InetAddress address) throws IOException {
        socket = new DatagramSocket();
        socket.setBroadcast(true);

        byte[] buffer = broadcastMessage.getBytes();

        DatagramPacket packet 
          = new DatagramPacket(buffer, buffer.length, address, 4445);
        socket.send(packet);
        socket.close();
    }
}

Следующий фрагмент показывает, как перебирать все Сетевые интерфейсы , чтобы найти их широковещательный адрес:

List listAllBroadcastAddresses() throws SocketException {
    List broadcastList = new ArrayList<>();
    Enumeration interfaces 
      = NetworkInterface.getNetworkInterfaces();
    while (interfaces.hasMoreElements()) {
        NetworkInterface networkInterface = interfaces.nextElement();

        if (networkInterface.isLoopback() || !networkInterface.isUp()) {
            continue;
        }

        networkInterface.getInterfaceAddresses().stream() 
          .map(a -> a.getBroadcast())
          .filter(Objects::nonNull)
          .forEach(broadcastList::add);
    }
    return broadcastList;
}

Как только у нас будет список широковещательных адресов, мы сможем выполнить код в методе broadcast () , показанном выше, для каждого из этих адресов.

Для получения широковещательного сообщения на принимающей стороне не требуется специального кода. Мы можем повторно использовать тот же код, который получает обычную дейтаграмму UDP. Руководство по UDP в Java содержит более подробную информацию по этой теме.

4. Многоадресная рассылка

Вещание неэффективно, поскольку пакеты отправляются всем узлам сети, независимо от того, заинтересованы ли они в получении сообщения или нет. Это может быть пустой тратой ресурсов.

Многоадресная рассылка решает эту проблему и отправляет пакеты только тем потребителям, которые заинтересованы. Многоадресная рассылка основана на концепции членства в группе , где адрес многоадресной рассылки представляет каждую группу.

В IPv4 в качестве многоадресного адреса можно использовать любой адрес в диапазоне от 224.0.0.0 до 239.255.255.255. Только те узлы, которые подписываются на группу, получают пакеты, переданные группе.

В Java MulticastSocket используется для приема пакетов, отправленных на IP-адрес многоадресной рассылки. В следующем примере показано использование MulticastSocket :

public class MulticastReceiver extends Thread {
    protected MulticastSocket socket = null;
    protected byte[] buf = new byte[256];

    public void run() {
        socket = new MulticastSocket(4446);
        InetAddress group = InetAddress.getByName("230.0.0.0");
        socket.joinGroup(group);
        while (true) {
            DatagramPacket packet = new DatagramPacket(buf, buf.length);
            socket.receive(packet);
            String received = new String(
              packet.getData(), 0, packet.getLength());
            if ("end".equals(received)) {
                break;
            }
        }
        socket.leaveGroup(group);
        socket.close();
    }
}

После привязки MulticastSocket к порту мы вызываем метод joinGroup() с IP-адресом многоадресной рассылки в качестве аргумента. Это необходимо для получения пакетов, опубликованных в этой группе. Для выхода из группы можно использовать метод LeaveGroup () .

В следующем примере показано, как опубликовать на многоадресном IP-адресе:

public class MulticastPublisher {
    private DatagramSocket socket;
    private InetAddress group;
    private byte[] buf;

    public void multicast(
      String multicastMessage) throws IOException {
        socket = new DatagramSocket();
        group = InetAddress.getByName("230.0.0.0");
        buf = multicastMessage.getBytes();

        DatagramPacket packet 
          = new DatagramPacket(buf, buf.length, group, 4446);
        socket.send(packet);
        socket.close();
    }
}

5. Широковещательная передача и IPv6

IPv4 поддерживает три типа адресации: одноадресную, широковещательную и многоадресную. Вещание, в теории, представляет собой связь “один ко всем”, то есть пакет, отправленный с устройства, может достичь всего Интернета.

Поскольку это нежелательно по очевидным причинам, объем широковещательной передачи IPv4 был значительно сокращен. Многоадресная рассылка, которая также служит лучшей альтернативой широковещательной передаче, появилась намного позже и, следовательно, отстала в принятии.

В IPv6 поддержка многоадресной рассылки стала обязательной, и нет явной концепции вещания. Многоадресная рассылка была расширена и улучшена, так что теперь все функции вещания могут быть реализованы с помощью той или иной формы многоадресной рассылки.

В IPv6 самые левые биты адреса используются для определения его типа. Для многоадресного адреса первые 8 бит-это все единицы, т. е. FF00::/8. Кроме того, бит 113-116 представляет область адреса, которая может быть одной из следующих 4: Глобальная, локальная для сайта, локальная для ссылки, локальная для узла.

В дополнение к одноадресной и многоадресной рассылке IPv6 также поддерживает anycast, в котором пакет может быть отправлен любому члену группы, но не обязательно всем членам.

6. Резюме

В этой статье мы рассмотрели концепции связи “один ко всем” и “один ко многим” с использованием протокола UDP. Мы видели примеры того, как реализовать эти концепции в Java.

Наконец, мы также изучили поддержку IPv4 и IPv6.

Полный пример кода доступен на Github .