前回は,現在のネットワークの基盤をなすネットワーク・プロトコルであるIP(Internet Protocol)と,LinuxカーネルのIPプロトコル・スタックについて解説しました。

 IPというプロトコルでは,2点間のデータ通信の方法しか定義していません。例えば,送信元が送ったデータが送信先に届いていなくてもIPでは関知しません。あくまで,このホストからこのホストにデータを送るにはこうすればいい,ということだけ規定してあるのです。つまり,細かい通信の制御や信頼性確保などは別のレイヤー(トランスポート層)で実施することになります。

 IPネットワークで利用される代表的なトランスポート層プロトコルが,「TCP」(Transmission Control Protocol)と「UDP」(User Datagram Protorol)です*1

 UDPは,IPをほとんどそのまま利用するだけのプロトコルで,主に信頼性をあまり必要としない通信に使われます。音声や映像のストリーミングでは,データ品質よりも即時性(リアルタイム性)を重視する場合があります。例えば,テレビ電話などでは,遅延が大きすぎると会話が難しくなります。遅延を減らすには,データが確実に送信されたかの確認や,通信エラーが生じた場合の再送処理などをせずに,どんどんデータを送り続けるのが効果的です。多少届かないデータがあったとしても,音声や映像では再生品質が劣化するだけで概ねの情報は得られますから,これでも問題ありません。

 一方,TCPでは,3ウェイ・ハンドシェイク(後述)といった形で通信経路を確保し,データの送受信の際も相手がきちんとデータを受け取ったことを確認するようになっています。スループット(実効通信速度)は多少落ちますが,送ったデータが確実に届くことが保証され,信頼性の高い通信が実現できます。

LinuxカーネルのUDP処理

 まずは,単純なプロトコルであるUDPについて解説します。前述したように,UDPはIPとほとんど変らないプロトコルです。ただし,通信路を指定する「ポート番号」の指定ができる点だけが異なっています。実際,UDPのパケットはIPのパケットにUDPヘッダーを付け,そこでポート番号を指定した構造になっています。

 このような簡単なプロトコルですから,Linuxの実装でも特に複雑なことはしていません。

図1●UDPレイヤーで生成されるUDPヘッダーの構造
図1●UDPレイヤーで生成されるUDPヘッダーの構造
チェックサム部分は,IPレイヤーに処理が移ってから計算されます。

 アプリケーションがソケットを用意し,UDPのパケット送信のシステム・コールを発行すると,ソケット・レイヤーを経由して,UDPレイヤーに処理が回ります。UDPレイヤーでは,図1のような仮のUDPヘッダーを作ってIPレイヤーの送信処理に渡します。これで分かるように1つのUDPパケットは,1 つのIPパケットに対応しています。

 仮のUDPヘッダーと書いたのは,まだこの時点ではUDPヘッダーのチェックサムが生成されていないからです。チェックサムが生成されないのは,計算対象の一部であるIPヘッダーが未生成であることが原因です。

 そこでIPレイヤーでは,IPヘッダーを生成したあと,UDPのコールバック関数を呼び出して,チェックサムを計算しUDPヘッダーに反映させます。正式なUDPヘッダーが生成できたら,(前回解説したように)IPレイヤーで送信処理を再開します。

 逆に受信時はどうなっているのでしょうか。以前解説した通り,Linuxでは,パケットを受信すると割り込み信号が発生します。パケットの受信処理は,デバイス・ドライバが登録した割り込みハンドラで実施されます。

 IPレイヤーでパケットの中身がUDPであると判断すると,その処理はUDPレイヤーに渡されます。UDPレイヤーでは,まず最初にパケットのチェックサムを計算し,それとUDPヘッダー部分のチェックサムを照合します。両者が一致しない場合は,処理をせずにパケットを破棄します。一致した場合は,受信したパケットの送信先ポート番号を調べます。そして,そのポートにバインドされている(そのポートを監視している)ソケットを探します。

 送信対象のソケットが見つかったら,そのソケットにパケットを配信します。つまり,ソケットの受信キューに登録します。その後,ソケットからのデータを待って待機中のプロセスを起床し,データの処理を実施します(図2)。

図2●UDPパケットの受信処理手順
図2●UDPパケットの受信処理手順
最終的には,データを待ち受けているソケットの受信キューにデータが登録されます。UDPパケットのチェックサムに問題がある場合,パケットは破棄されます。

 受信プロセスは,recv()システム・コールなどを発行して,ソケットからのデータを待ち受けています。UDPパケット到着後,カーネルはプロセスにデータを渡しますが,その際にUDPパケットは破棄します。プロセスが要求したデータ・サイズが到着したパケットのデータ・サイズより小さかったとしても,残りの部分も一緒に破棄してしまいます。これは,UDPプロトコル・スタックの仕様です。