最近こんな話ばっかですが、ロミオとジュリエットっていうすっごく有名なお話があります。これを強引に通信プロトコルの話に持っていきます。ひどい。
ロミオとジュリエットのあらすじ。ナントカ家とカントカ家の間には争いが絶えずたびたび暴力衝突さえ起きるような仲の悪い両家、そのそれぞれの息子と娘であるロミオとジュリエットが恋に落ちたというお話。
しかし二人が仲良くする一方で両家の軋轢は苛烈を極め、ついに殺人にまで発展。親友を殺されたロミオは激怒し、報復。もちろん報復とはいえ許されるわけではないのでロミオは国外追放となってしまいます。
ロミオ追放後、名家への輿入れを強制されたジュリエットはロミオと添い遂げるために一計を講じます。それは、仮死状態になる薬で一旦死に、葬儀が終わってから国外でロミオと落ち合うという策。このため、二人を応援する仲人を介してこの作戦をロミオに伝えるべく使者を送ります。
ところが使者は国外のロミオにたどり着けず、一方、ジュリエットはそれを知らずに作戦を決行。ジュリエットは死んだことになり、この死を伝える使者があろうことかロミオにたどり着きそれを伝えてしまいます。ロミオは後を追い、目覚めたジュリエットも後を追ってしまうという悲劇です。
さて、なぜこんな悲劇になってしまったのか、ポイントは二つあります。
一つは、「ジュリエットはロミオへの信号路を確立していなかったこと」、もう一つは「より上位プロトコルとしての『メッセージの伝達』と『メッセージを理解したことの返答(ACK)』を実装していなかったこと」の二つになるかと思います。
一つ目は、ロミオにメッセージを伝える使者が、ロミオの居場所を知らなかったことです。最初からロミオの居場所を確認できていれば、使者は正しくロミオのところにたどり着いたはずです。たとえば、事前にロミオが正しく応答できるかどうかのチェックのための使者を届けます。ロミオがこの使者に「ちゃんと聞ける状態になりました」と返答し、それを確認したジュリエットは、「では今からメッセージを送るのでその場所から動かないでください」と使者を送っておく、これだけで、続く使者が確実に到達する可能性は極めて高くなります。
これは、TCPでいうところの3wayハンドシェイクです。あらかじめ3wayハンドシェイクを行うことで相手が受信可能な状況である可能性をほどほどに高めることができます。また、TCPではさらにパケット一つ一つについて受信確認を行うプロトコルを実装しているので、ロミオ-ジュリエットプロトコル(opt1)においても、使者がたどり着いたかどうかを毎回チェックすることでより通信路の確実性を上げることができたでしょう。
もう一つの問題である「上位プロトコルの実装不足」。これは、仮にTCPを使わずより不確実なUDPを使ってプロトコルを実装せざるを得ない(事前ハンドシェイクやACK待ちなどの時間的ロスが許されないなど)という状況では、より上位で実際のアプリケーションの性質に従った実装を行うべきであるという話。
この話も、実際にジュリエットは輿入れの期限が近く、3wayハンドシェイクを行う時間が無かったと思われ、やむを得ずUDPを使ったのである、と解釈することも可能です。そうであれば、アプリケーションレベルの実装(仮にロミオ-ジュリエットプロトコルopt2)として、ロミオへのメッセージに「仮死状態になって脱出します、これが可能であるという返答あり次第決行です」と書いておくことで、ロミオは自分の返答が求められていると理解することができます(メッセージ伝達とロミオへのロミオ-ジュリエットプロトコルopt2のプログラミングまでしてしまう高度な伝達です)。ジュリエットは、ロミオからの返答を持った使者が来ない場合、ロミオにメッセージが伝わっていないとみなして同じメッセージを持たせた使者を次々と送って伝達性を高めることが可能です。
たとえばUDPを使うSIPなどにおいても、SIPのレベルでのACKの仕組みが備わっていて、間でパケットが失われた可能性を検出できるようになっています。より確実には、使者の伝達自体はロミオ-ジュリエットプロトコルopt1で保証し、メッセージ内容である作戦の決行可否を上位のロミオ-ジュリエットプロトコルopt2でネゴシエーションすることで確実に作戦を決行することができるように実装しておくことが理想です。
実際の通信でもおおよそこういうことは行われていて、たとえば携帯電話において、データ通信をするためのインターネットへのチャネルを開きたい、と言う一つの作戦の成立に対しては、下位の信号伝達はHybridARQなどで保証し、その上位で端末と基地局の能力情報を交換しお互いが選択可能なチャネル種別をネゴシエーションすることで作戦(回線確立)を実現する、と言う仕組みになっています。
もしこれを、ジュリエットが最初に採用した一切の信号保証なしかつ上位ACKも無し、と言うロミオ-ジュリエットプロトコルopt0で実現しようとするとどうなるか。端末が通信を開始したい場合、基地局に向けて「XXXと言うコンフィグの50Mbpsのチャネルを開きますので」と伝えていきなり無線機のXXXコンフィグを開いて待っているようなもの。もしその最初の信号が基地局に届いていなければもちろん基地局は何もできませんし、届いたとしても「XXXとかいうコンフィグ無理だよぅ」と言ってやはり基地局は何もできないかもしれません。しかしそれさえ端末は知らずに無駄にXXXコンフィグの無線機をフルパワーで動かしていますから、あっという間にバッテリー枯渇です。
実際には、「データ路が欲しいです、私にできるのはXXX、YYY、ZZZと言うコンフィグです」と送ります。もちろん、それが基地局に届いたかどうかをチェックする機構(ランダムアクセスや再送)もあるので、届いていないと判断した場合は同じメッセージをもう一回送ります(実際はいつも完全な再送になるとは限りませんが)。基地局はそれを受け取れた場合に、今度はその内容を解釈します。「データ路が欲しいこと」「端末が可能なコンフィグのセット」などの情報から、たとえば「おっけー、XXXのコンフィグなら可能なので通信路開いてください」と送ります。下位の伝達保証プロトコルでそれが端末に届いたことが分かった段階で基地局はXXXコンフィグに合わせたチャネル送信を開始する、と言う感じです。もちろん、基地局がXXX、YYY、ZZZいずれのコンフィグにも対応不可能だったり、混雑していてリソースを確保できない場合などは「無理ですごめんね」と言う返答をすることも可能です。ロミオ-ジュリエットプロトコルopt1とopt2の考え方だけで、ほぼ実際の携帯電話におけるチャネルネゴシエーションの仕組みを説明できてしまいます。
と言うことで、ロミオとジュリエットの悲劇は、通信プロトコルについての理解が非常に浅かったジュリエットの失敗によって起きたということができます。こういった考え方は通信に関してはほぼ基礎的な技術に近いものであり、新しいタイプの通信を実現しようとしたジュリエットがどうしてこのレベルの基礎的な実装を仕様から漏らしてしまったのか、と言う点で極めて重(以下2000字略