Lesson1~2で見たように,UDPはアプリケーション同士を橋渡しするポート番号だけを管理し,それ以外のしくみを省略することで「軽さ」を実現している。

 このため,ただ単純にUDPを使ってデータを運ぼうとすると,データはどんどん送り出せるけれど,相手に届く保証はまったくないという,信頼性がきわめて低い通信になってしまう(図3-1)。

図3-1●UDPそのものは通信の信頼性を高めるしくみを備えていない
図3-1●UDPそのものは通信の信頼性を高めるしくみを備えていない
UDPの仕事はポート番号の管理だけで,紛失したパケットを再送するといった通信を制御するしくみは備えていない。パケットが途中でなくなろうが順番が入れ替わろうが,まったく関知せずやりとりを続ける。  [画像のクリックで拡大表示]

 送信側のUDPスタックは,UDPパケットを送ったら,送りっ放しであとは知らんぷり。受信側のUDPスタックも,UDPパケットが届こうが届くまいがおかまいなしだ。

 こんな通信しかできなければ,いくら処理が軽いからといっても,UDPを使う意味はない。

アプリ側で処理をまかなう

 ではどうすればいいか。まず考えられるのは,UDP自体に何とか信頼性を持たせられないかということだろう。しかし,Lesson1で見たようにそれは不可能だ。UDPヘッダーには通信の制御に使える空き領域は1ビットも存在しない。

 UDPに頼れないなら,残された手は一つ。アプリケーションが自ら工夫して信頼性を確保するしかない。パケットが途中でなくなったら再送し,データがあふれそうになったらパケットの流量を調整し,パケットの順番が入れ替わっても大丈夫なように番号を付けておく──。こうした制御をアプリケーションが主体となって行うことで,UDPの特性を生かしつつ信頼性のある通信を実現できる。

 実際に,世の中で使われているUDPアプリケーションの多くは,こうした信頼性確保のための制御のしくみを持っている。ここでは,そうした制御のしくみのうち,最も基本的な「パケットの再送制御」について見ておこう。

アプリ自身がタイマーで監視

 UDPを使うアプリケーションがパケットの再送制御を実現するには,「そもそも送信したパケットが相手に届かないことをどうやって判断するのか」がポイントとなる。一般に,その判断にはアプリケーション自身が管理する「再送タイマー」を使う(図3-2)。

図3-2●通信の信頼性はアプリケーション側で高める
図3-2●通信の信頼性はアプリケーション側で高める
TCPを使うアプリケーションの場合,TCPに通信の信頼性確保のための制御をすべて任せておける。一方,UDPはそうした制御を何ひとつしないので,上位アプリケーションが自ら信頼性を高めるための制御をするしかない。  [画像のクリックで拡大表示]

 UDPアプリケーションは,パケットの送信をUDPスタックに依頼したあとすぐにタイマーを使って時間を計り始める。そして,もし一定時間内に相手からの応答が返ってこなかったらパケットがなくなったと判断し,同じデータを再送信する。同様に,相手側のアプリケーションでもタイマーを使って再送制御をすることで,通信経路上でたまたまパケットが紛失したことによる通信の失敗を避けられるわけだ。

 ただし,相手から応答パケットが返ってこなかったからといって,必ずしもパケットが経路上で紛失しているとは限らない。相手のアプリケーションがパケットの受け取りを拒否したり,返事を返さず捨てている可能性もある。そんな状況でひたすら再送し続けても無駄なだけだ。

 そこで多くのUDPアプリケーションは,タイマーによる再送制御機能に加えて,永遠に再送し続けないように処理する機能も併せ持つ。「3回送ってダメだったらやめる」とか「再送信のたびに送信間隔を広げる」といった具合だ。

 具体例を挙げると,IP電話の制御用プロトコルであるSIPの場合,「相手を呼び出すINVITE(インバイト)リクエストは,相手から応答がなかったら最初は0.5秒,次は1秒という具合に送信間隔を2倍ずつ増やしていきながら最大6回までパケットを再送する」(ソフトフロントの佐藤 和紀・SPP事業本部長)ようになっている。UDPを使っても,工夫次第でTCP並みに信頼性を高められるのである。