Nadawanie i multiemisja w Javie

1. Wstęp

W tym artykule opisujemy, jak komunikacja typu jeden do wszystkich (emisja) i jeden do wielu (multiemisja) może być obsługiwana w języku Java. Koncepcje emisji i multiemisji opisane w tym artykule są oparte na protokole UDP.

Zaczynamy od szybkiego podsumowania datagramów i transmisji oraz sposobu ich implementacji w Javie. Analizujemy również wady nadawania i proponujemy multiemisję jako alternatywę dla nadawania.

Na koniec omawiamy obsługę tych dwóch metod adresowania zarówno w protokole IPv4, jak i IPv6.

2. Podsumowanie datagramów

Zgodnie z oficjalną definicją datagramu „Datagram to niezależna, samodzielna wiadomość wysyłana przez sieć, której nadejście, czas przybycia i zawartość nie są gwarantowane”.

W języku Java pakiet java.net udostępnia klasy DatagramPacket i DatagramSocket , których można używać do komunikacji za pośrednictwem protokołu UDP. Protokół UDP jest zwykle używany w scenariuszach, w których mniejsze opóźnienia są ważniejsze niż gwarantowane dostarczanie, takich jak przesyłanie strumieniowe audio / wideo, wykrywanie sieci itp.

Aby dowiedzieć się więcej o UDP i datagramach w Javie, zapoznaj się z Przewodnikiem po UDP w Javie.

3 . Nadawanie

Broadcasting to komunikacja typu „jeden do wszystkich”, tj. Celem jest wysłanie datagramu do wszystkich węzłów w sieci. W przeciwieństwie do komunikacji punkt-punkt, nie musimy znać adresu IP hosta docelowego . Zamiast tego używany jest adres rozgłoszeniowy.

Zgodnie z protokołem IPv4 adres rozgłoszeniowy to adres logiczny, na którym urządzenia podłączone do sieci mogą odbierać pakiety. W naszym przykładzie używamy konkretnego adresu IP, 255.255.255.255 , który jest adresem rozgłoszeniowym sieci lokalnej.

Z definicji routery łączące sieć lokalną z innymi sieciami nie przekazują dalej pakietów wysyłanych na ten domyślny adres rozgłoszeniowy. Później pokażemy również, jak możemy iterować przez wszystkie interfejsy sieciowe i wysyłać pakiety na ich adresy rozgłoszeniowe.

Najpierw pokazujemy, jak nadać wiadomość. W tym celu musimy wywołać metodę setBroadcast () na gnieździe, aby dać mu znać, że pakiet ma zostać wysłany :

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

Następny fragment pokazuje, jak iterować przez wszystkie NetworkInterfaces, aby znaleźć ich adres rozgłoszeniowy:

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

Gdy mamy już listę adresów rozgłoszeniowych, możemy wykonać kod w metodzie broadcast () pokazanej powyżej dla każdego z tych adresów.

Nie jest wymagany żaden specjalny kod po stronie odbiorcy, aby odebrać nadawaną wiadomość. Możemy ponownie użyć tego samego kodu, który otrzymuje normalny datagram UDP. Przewodnik po UDP w Javie zawiera więcej szczegółów na ten temat.

4. Multiemisja

Nadawanie jest nieefektywne, ponieważ pakiety są wysyłane do wszystkich węzłów w sieci, niezależnie od tego, czy są one zainteresowane otrzymywaniem komunikacji, czy nie. Może to być strata zasobów.

Multiemisja rozwiązuje ten problem i wysyła pakiety tylko do zainteresowanych konsumentów. Multiemisja jest oparta na koncepcji członkostwa w grupie , gdzie adres multiemisji reprezentuje każdą grupę.

W protokole IPv4 każdy adres z zakresu od 224.0.0.0 do 239.255.255.255 może być użyty jako adres multiemisji. Tylko te węzły, które subskrybują grupę, odbierają pakiety przesłane do grupy.

W Javie, MulticastSocket służy do odbierania pakietów wysyłanych na adres IP multiemisji. Poniższy przykład demonstruje użycie 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(); } }

Po powiązaniu MulticastSocket z portem wywołujemy metodę joinGroup () z adresem IP multiemisji jako argumentem. Jest to konieczne, aby móc odbierać pakiety publikowane w tej grupie. Do opuszczenia grupy można użyć metody leaveGroup () .

Poniższy przykład pokazuje, jak publikować na adresie IP multiemisji:

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. Transmisja i IPv6

IPv4 obsługuje trzy typy adresowania: unicast, broadcast i multicast. Broadcast teoretycznie to komunikacja typu „jeden do wszystkich”, tj. Pakiet wysłany z urządzenia ma potencjał dotarcia do całego internetu.

Ponieważ jest to niepożądane z oczywistych powodów, zakres transmisji IPv4 został znacznie ograniczony. Multiemisja, która służy również jako lepsza alternatywa dla nadawania, pojawiła się znacznie później i dlatego opóźniała się w przyjęciu.

W IPv6 obsługa multiemisji stała się obowiązkowa i nie ma wyraźnej koncepcji rozgłaszania. Multiemisja została rozszerzona i ulepszona, dzięki czemu wszystkie funkcje rozgłaszania można teraz zaimplementować za pomocą jakiejś formy multiemisji.

W protokole IPv6 skrajne lewe bity adresu służą do określenia jego typu. W przypadku adresu multiemisji pierwsze 8 bitów to wszystkie jedynki, tj. FF00 :: / 8. Ponadto bity 113-116 reprezentują zakres adresu, który może być jednym z następujących 4: Globalny, Lokalny dla lokalizacji, Lokalny dla łącza, Lokalny dla węzła.

Oprócz emisji pojedynczej i multiemisji, IPv6 obsługuje również transmisję anycast, w której pakiet może zostać wysłany do dowolnego członka grupy, ale nie musi być wysyłany do wszystkich członków.

6. Podsumowanie

W tym artykule zbadaliśmy koncepcje komunikacji jeden do wszystkich i jeden do wielu przy użyciu protokołu UDP. Widzieliśmy przykłady implementacji tych koncepcji w Javie.

Na koniec zbadaliśmy również obsługę IPv4 i IPv6.

Pełny przykładowy kod jest dostępny na Github.