ネットワークについて語るとき、OSI モデルについて触れずにはいられません。

このモデルに関して、今日私たちが最も興味を持っているのはトランスポート層 (4) です。

これは、「ポイント A からポイント B へ」移動するデータを扱うレベルです。トランスポート層の主なタスクは、正しい順序を維持しながら、メッセージが宛先に確実に配信されるようにすることです。最も一般的な 2 つのトランスポート層プロトコルは、TCP と UDP です。これらは概念的には異なる方法で機能しますが、それぞれに特定の問題を解決できる独自の利点があります。

まず、TCP がどのように動作するかを見てみましょう。

TCP (Transmission Control Protocol) は、データが交換される前にホスト間の接続が確実に確立されるようにするネットワーク プロトコルです。

これは、別のデータ パケットを送信するたびに、前のパケットが受信されたかどうかを確認する必要があるため、非常に信頼性の高いプロトコルです。

送信されるパケットには順序があり、特定のパケットに問題がある場合(つまり、受信側がパケットの到着を確認しない場合)、パケットは再送信されます。その結果、厳密な監視と正しい順序付けを保証するためにより多くの時間が必要となるため、転送速度は比較的低くなります。

ここで、その「兄弟」である UDP プロトコルが登場します。TCP とは異なり、UDP は各パケットの順序やステータスをあまり気にしません。配信確認なしでデータを送信するだけです。さらに、接続は確立されず、接続ステータスにはまったく依存しません。

その目的は単にデータをアドレスに送信することです。そしてこれにより、データの一部が失われる可能性があるため、プロトコルの主な欠点である信頼性が低くなります。さらに、受信者は、データが順序どおりに到着しない可能性があるという事実に備える必要があります。とはいえ、このプロトコルにはデータの送信に限定されているため、転送速度が高いという利点もあります。

データ自体の送信方法にも違いがあります。TCP では、データはストリーミングされます。これは、データに境界がないことを意味します。UDP では、データはデータグラムとして送信され、境界があり、受信者はデータの整合性をチェックしますが、これはメッセージが正常に受信された場合に限られます。

要約しましょう:

TCP は、データ損失を防ぐ信頼性が高く正確なプロトコルです。メッセージは常に最高の精度で配信されるか、まったく配信されません。受信データはすでに順序付けされているため、受信者はデータを順序付けるためのロジックを必要としません。 UDP は信頼性はそれほど高くありませんが、より高速なデータ転送プロトコルです。このプロトコルを使用するには、送信側と受信側に追加のロジックが必要です。しかし、ネットワーク経由でプレイされるコンピューター ゲームやモバイル ゲームを例にして、その仕組みを見てみましょう。5 秒前に到着するはずだったものはもう気にしないかもしれません。時間通りに到着しない場合は、いくつかのパケットをスキップできます。ゲームにラグが生じる可能性がありますが、それでもプレイすることはできます。

Java では、UDP 経由で送信されるデータグラムを処理するために、DatagramSocketクラスとDatagramPacketクラスのオブジェクトを使用します。

データを交換するために、送信者と受信者はデータグラム ソケット、つまりDatagramSocketクラスのインスタンスを作成します。クラスには複数のコンストラクターがあります。それらの違いは、作成されたソケットが接続される場所です。

データグラムソケット () ローカルマシン上の利用可能なポートに接続します
DatagramSocket (int ポート) ローカルマシン上の指定されたポートに接続します
DatagramSocket(int ポート、InetAddress アドレス) ローカル マシン上のアドレス (addr) の指定されたポートに接続します。

このクラスには、ソケット パラメーター (後で説明します) にアクセスして管理するための多くのメソッドと、データグラムを送受信するためのメソッドが含まれています。

send(データグラムパケットパック) データグラムをパケットに詰めて送信します
受信(データグラムパケットパック) パケットにパックされたデータグラムを受信します

DatagramPacket は、データグラム パッケージを表すクラスです。データグラム パケットは、コネクションレス型パケット配信サービスを実装するために使用されます。各メッセージは、そのパケットに含まれる情報のみに基づいて、あるマシンから別のマシンにルーティングされます。あるマシンから別のマシンに送信される複数のパケットは、異なるルートでルーティングされ、任意の順序で到着する可能性があります。パケットの配信は保証されません。

コンストラクター:

DatagramPacket(byte[] buf, int length) 長さlengthのパケットを受け入れるDatagramPacketを作成します。
DatagramPacket(byte[] buf、int 長、InetAddress アドレス、int ポート) データグラム パケットを作成して、指定されたホスト上の指定されたポート番号に長さlengthのパケットを送信します。
DatagramPacket(byte[] buf, int オフセット, int 長) バッファ内のオフセットを指定して、長さlengthのパケットを受け入れるDatagramPacketを作成します。
DatagramPacket(byte[] buf、int オフセット、int 長、InetAddress アドレス、int ポート) データグラム パケットを作成し、指定されたホスト上の指定されたポート番号にオフセットoffsetを使用して長さlengthのパケットを送信します。
DatagramPacket(byte[] buf、int オフセット、int 長、SocketAddress アドレス) データグラム パケットを作成し、指定されたホスト上の指定されたポート番号にオフセットoffsetを使用して長さlengthのパケットを送信します。
DatagramPacket(byte[] buf, int 長, SocketAddress アドレス) データグラム パケットを作成して、指定されたホスト上の指定されたポート番号に長さlengthのパケットを送信します。

UDP アプローチでは接続が確立されないことを思い出してください。パケットは、受信者がパケットを期待していることを期待して送信されます。ただし、 DatagramSocketクラスのconnect(InetAddress addr, int port)メソッドを使用して接続を確立できます。

データグラムを送信または受信するために、アドレスとポートに基づいてホストとの一方向接続が確立されます。接続は、disconnect()メソッドを使用して終了できます。

DatagramSocketに基づいてデータを受信するサーバー コードを作成してみましょう。

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;

class Recipient {

   public static void main(String[] args) {
       try {
           DatagramSocket ds = new DatagramSocket(1050);

           while (true) {
               DatagramPacket pack = new DatagramPacket(new byte[5], 5);
               ds.receive(pack);
               System.out.println(new String(pack.getData()));
           }
       } catch (IOException e) {
           e.printStackTrace();
       }
   }
}

ポート 1050 でリッスンするDatagramSocketオブジェクトを作成します。メッセージを受信すると、それをコンソールに出力します。「Hello」という単語を送信するので、バッファ サイズを 5 バイトに制限します。

次に、送信者クラスを作成します。

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

class Sender {
   private String host;
   private int port;

   Sender(String host, int port) {
       this.host = host;
       this.port = port;
   }

   private void sendMessage(String mes) {
       try {
           byte[] data = mes.getBytes();
           InetAddress address = InetAddress.getByName(host);
           DatagramPacket pack = new DatagramPacket(data, data.length, address, port);
           DatagramSocket ds = new DatagramSocket();
           ds.send(pack);
           ds.close();
       } catch (IOException e) {
           System.err.println(e);
       }
   }

   public static void main(String[] args) {
   Sender sender = new Sender("localhost", 1050);
   String message = "Hello";

   Timer timer = new Timer();
   timer.scheduleAtFixedRate(new TimerTask() {
       @Override
       public void run() {
           sender.sendMessage(message);
       }
   }, 1000, 1000);
}

}

sendMessageメソッドでDatagramPacketDatagramSocketを作成し、メッセージを送信します。close()メソッドは、メッセージの送信後にDatagramSocketを閉じるために使用されることに注意してください。

受信者のコンソールには、送信者から送信された受信「Hello」メッセージが毎秒表示されます。これは、私たちのコミュニケーションがすべて正しく機能していることを意味します。