Перейти к основному содержимому

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

· 5 мин. чтения

1. Введение

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

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

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

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

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

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

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

3 . Вещание

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

В соответствии с протоколом 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();
}
}

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

List<InetAddress> listAllBroadcastAddresses() throws SocketException {
List<InetAddress> broadcastList = new ArrayList<>();
Enumeration<NetworkInterface> 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;
}

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

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

6. Резюме

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

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

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