1. 序章

この記事では、Javaで1対多(ブロードキャスト)および1対多(マルチキャスト)の通信を処理する方法について説明します。 この記事で概説されているブロードキャストおよびマルチキャストの概念は、UDPプロトコルに基づいています。

まず、データグラムとブロードキャストの簡単な要約と、それがJavaでどのように実装されているかを説明します。 また、放送のデメリットを調査し、放送に代わるマルチキャストを提案します。

最後に、IPv4とIPv6の両方でのこれら2つのアドレッシング方式のサポートについて説明します。

2. データグラムの要約

データグラムの公式定義によると、「データグラムは、ネットワークを介して送信される独立した自己完結型のメッセージであり、到着、到着時間、およびコンテンツは保証されません」。

Javaでは、 java.net パッケージは、UDPプロトコルを介した通信に使用できるDatagramPacketおよびDatagramSocketクラスを公開します。 UDPは通常、オーディオ/ビデオストリーミング、ネットワーク検出など、保証された配信よりも低遅延が重要なシナリオで使用されます。

JavaでのUDPとデータグラムの詳細については、JavaでのUDPガイドを参照してください。

3放送

ブロードキャストは、1対1のタイプの通信です。 目的は、ネットワーク内のすべてのノードにデータグラムを送信することです。 ポイントツーポイント通信の場合とは異なり、ターゲットホストの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();
    }
}

次のスニペットは、すべてのNetworkInterfacesを反復処理してブロードキャストアドレスを見つける方法を示しています。

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

ブロードキャストアドレスのリストを取得したら、これらのアドレスごとに上記の broadcast()メソッドのコードを実行できます。

ブロードキャストメッセージを受信するために受信側に特別なコードは必要ありません。 通常のUDPデータグラムを受信するのと同じコードを再利用できます。 JavaでのUDPガイドには、このトピックの詳細が含まれています。

4. マルチキャスト

パケットは、通信の受信に関心があるかどうかに関係なく、ネットワーク内のすべてのノードに送信されるため、ブロードキャストは非効率的です。 これはリソースの浪費である可能性があります。

マルチキャストはこの問題を解決し、関心のある消費者にのみパケットを送信します。 マルチキャストはグループメンバーシップの概念に基づいており、マルチキャストアドレスは各グループを表します。

IPv4では、224.0.0.0〜239.255.255.255の任意のアドレスをマルチキャストアドレスとして使用できます。 グループにサブスクライブしているノードのみが、グループに通信されたパケットを受信します。

Javaでは、 MultimediaSocket は、マルチキャストIPに送信されたパケットを受信するために使用されます。 次の例は、MultimediaSocketの使用法を示しています。

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

MultimediaSocket をポートにバインドした後、マルチキャストIPを引数として、 joinGroup()メソッドを呼び出します。 これは、このグループに公開されたパケットを受信できるようにするために必要です。 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は、ユニキャスト、ブロードキャスト、およびマルチキャストの3種類のアドレス指定をサポートしています。 理論的には、ブロードキャストは1対1の通信です。 デバイスから送信されたパケットは、インターネット全体に到達する可能性があります。

これは明らかな理由で望ましくないため、IPv4ブロードキャストの範囲は大幅に縮小されました。 放送のより良い代替手段としても機能するマルチキャストは、はるかに遅れて登場したため、採用が遅れました。

IPv6では、マルチキャストサポートが必須になり、ブロードキャストの明確な概念はありません。マルチキャストが拡張および改善され、すべてのブロードキャスト機能を何らかの形式のマルチキャストで実装できるようになりました。

IPv6では、アドレスの左端のビットがそのタイプを決定するために使用されます。 マルチキャストアドレスの場合、最初の8ビットはすべて1です。 FF00 ::/8。 さらに、ビット113〜116はアドレスのスコープを表し、次のいずれかになります。グローバル、サイトローカル、リンクローカル、ノードローカル。

ユニキャストとマルチキャストに加えて、IPv6はエニーキャストもサポートしています。エニーキャストでは、パケットをグループの任意のメンバーに送信できますが、すべてのメンバーに送信する必要はありません。

6. 概要

この記事では、UDPプロトコルを使用した1対多および1対多のタイプの通信の概念について説明しました。 これらの概念をJavaで実装する方法の例を見ました。

最後に、IPv4とIPv6のサポートについても検討しました。

完全なサンプルコードは、Githubから入手できます。