10-4: パケットとデータグラム通信


・ さてソケットには TCP以外のプロトコルの通信方法が存在します。 このプロトコルは UDPという名前で、 UDPによる通信を「データグラム型」と呼びます。 TCPでは互いが確認を取り合いながら通信を行います。 そのため万一エラーが発生してもデータの再発送が行われるため 「正確さ」が保証されます。 一方 UDPではデータは1回送信されるだけでチェックは行われません。 このような2種類の異なる方式が併存しているのは実用上の要求からです。 ネットワークの通信においては、 常に「速さ」と「正確さ」という2つの要素が求められます。 しかし、この両者は必ずしも両立が容易ではありません。 どちらか一方を優先すれば、どうしても他方を犠牲にすることになります。 単一のプロトコルで両者の要求を満足させるのは無理があります。 このため「速さ」を優先する UDP と「正確さ」を優先する TCP が存在するわけです。
 TCPも UDPもデータの送受信に「パケット(packet)」 とというデータの単位を用います。 TCPが この IPの層の上にさらにプロトコルを定義しているのに対して、 UDPの通信は IPのパケットの直接のやりとりそのものです。

通信方式の比較とjava.netのクラス
プロトコル通信の型利用の目的 ソケットのクラスデータ入出力
TCPコネクション型正確さを優先 Socketストリーム
UDPデータグラム型速さを優先 DatagramSocketパケット

 それでは UDPによる通信プログラムのサンプルを紹介しましょう。 パケットを送信する側を PacketSender、受け取る側を PacketReceiver という名前にします。 まず PacketSender.java から見てみましょう。

 データグラム型の通信を行うためのソケットのクラスが DatagramSocketです。 この他にパケットを取り扱うための DatagramPacketクラスのオブジェクトが 必要になります。 送信側では、 この DatagramPacketクラスのオブジェクトに必要な情報である 通信データの内容、パケットのサイズ、送り先のマシンを与えて生成します。
 データの送信は DatagramSocket の send()メソッドによって実行されます。 TCPの時のようにストリームによる通信ではありません。 プログラムの構造は UDPによる通信の方が単純であることがわかるでしょう。 ただしパケットを直接扱うため、 パケットのサイズ、byte型の配列などの取り扱いが生じ少し煩雑になります。

 データを受け取る PacketReceiver.java の方もプログラムに違いがあまりありません。 TCPの時のように互いの「コネクションを張る」必要がないため、 ソケットの生成に当たる部分はずっと単純です。 受け取り側も単に DatagramSocket のオブジェクトを生成し、 ネットワークへの「口」を確保します。
 後は、この口にパケットが送られてくるのを待つだけです。 その仕事は DatagramSocketの receive()メソッドが行います。 ところで厳密に言うと java.net の DatagramPacketクラスは、 ネットワーク上を行き来するパケットそのものではありません。 むしろパケットを格納しておくための「箱」のようなイメージを持った方が、 プログラムの記述を理解しやすいでしょう。 したがって、 受け取り側でも最初に空の DatagramPacket のオブジェクトを生成します。 receive()メソッドには、このオブジェクトを引数として渡します。 パケットが受け取られた時点で、 このオブジェクトに中に情報が格納されます。
 上のサンプルプログラムの実行手順は、 先のサーバー/クライアントの場合と同じです。 まず PacketReceiver の側を起動し、 それを確認してから PacketSender を起動します。 この時に PacketReceiver が実行されているマシン名をコマンドライン引数に 与えてください。 PacketReceiver と PacketSender の関係は、 一見するとサーバとクライアントの関係のように見えます。 しかし、TCPの時のような通信の確認は行われません。 実際、PacketReceiverが起動される以前に PacketSenderを起動しても、 PacketSender自身はエラーにはならず正常終了します。 (比較のため試してみるといいでしょう。) この場合、送信されたパケットは誰にも受け取られず「行方不明」と なってしまいます。
 PacketSenderの側を書き換えて、定期的にパケットを繰り返し発送するように すれば、起動の順序を変えても通信は可能です。 あるいは、とりあえずパケットを送ってみて、相手が返事を返してくれるか 調べることを目的とするプログラムも記述できます。