Вещание и многоадресная передача на Java

Вещание и многоадресная передача на Java

1. Вступление

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

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

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

2. Резюме дейтаграммы

Согласноofficial definition дейтаграммы, «дейтаграмма - это независимое, автономное сообщение, отправляемое по сети, прибытие, время прибытия и содержимое которого не гарантируются».

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

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

3. Broadcasting

Вещание - это общение одного типа, т.е. намерение состоит в том, чтобы отправить дейтаграмму всем узлам сети. Unlike in the case of point-to-point communication,we don’t have to know the target host’s IP Address. Вместо этого используется широковещательный адрес.

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

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

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

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();
    }
}

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

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(), показанный выше, для каждого из этих адресов.

Естьno special code required on the receiving side для получения широковещательного сообщения. Мы можем повторно использовать тот же код, который получает обычную дейтаграмму UDP. A Guide to UDP in Java содержит более подробную информацию по этой теме.

4. Multicasting

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

Многоадресная рассылка решает эту проблему и отправляет пакеты только тем заинтересованным потребителям. Multicasting is based on a group membership concept, где групповой адрес представляет каждую группу.

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

В JavaMulticastSocket используется для приема пакетов, отправленных на многоадресный 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 был значительно сокращен. Многоадресная передача, которая также служит лучшей альтернативой вещанию, появилась намного позже и, следовательно, отстала в принятии.

In IPv6, multicast support has been made mandatory, and there is no explicit concept of broadcasting. Многоадресная рассылка была расширена и улучшена, поэтому теперь все функции широковещательной рассылки могут быть реализованы с помощью некоторой формы многоадресной рассылки.

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

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

6. Резюме

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

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

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