VI. ネットワーク操作の非形式的説明
ここでは、ネットワーク利用の 3 つの主要なフェーズ、すなわち開設、フロー制御、切断の間に行われる操作を叙述する。
A. 開設
データ送信のための接続を確立するには、一対の RFC を交換しなければならない。RTS は受信側から送信側へ送られなければならず、STR は送信側から受信側へ発行されなければならない。さらに、受信側は RTS の中でリンク番号を指定しなければならない。これらの RFC(RFC は RTS と STR を包含する総称である)は、どのような時間順序で発行されてもよい。また、保留中の呼び出し(すなわち、ユーザプログラムがまだ処理していない RFC)をキューイングする仕組みも用意しなければならない。これにより、ユーザは接続を使い終えたとき、別のプロセスからの次の保留中の呼び出しを調べ、その接続要求を受け入れるか拒否するかを決めることができる。ただし、ユーザが保留中の呼び出しを調べないことを選ぶ場合があるため、問題が生じる。その場合、それらの呼び出しは NCP 内のキュー領域を占有するだけになる。この問題に対するいくつかの代替解決策については後で述べる。
上述の試作システムコールの枠組みを用いると、接続の開設に成功するまでの時間的な順序として、少なくとも 4 つのものが考えられる。
- ユーザは LISTEN を発行し、自分に RFC を送ってくる相手なら誰とでも接続を検討する意思があることを示す。RFC が到着するとユーザに通知される。ユーザはそのソケットと接続したいかどうかを判断し、その判断に基づいて ACCEPT または CLOSE を発行する。「切断」の項で論じるように、CLOSE は接続を「拒否(refuses)」する。ACCEPT は接続する意思があることを示し、RFC が発行されて接続は完全に開設される。
- ユーザの LISTEN 要求を処理する際に、NCP はそのローカルソケットに対する保留中の呼び出しが存在することを発見する。ユーザには直ちに通知され、上記と同様に ACCEPT または CLOSE を行うことができる。
- ユーザは CONNECT を発行し、接続したい特定の外部ソケットを指定する。RFC が発行される。外部プロセスが要求を受け入れると、RFC を返すことで応答する。この確認応答の RFC を受信すると、接続が開設される。
- CONNECT を受けたとき、NCP は、指定された外部ソケットから当該ローカルソケットへの保留中の呼び出しが存在することを発見する場合がある。確認応答の RFC が発行され、接続が開設される。
上記のいずれの場合も、接続が開設されるとユーザに通知されるが、バッファ領域が割り当てられ ALL コマンドが送信されるまでデータの流れは開始できない。
「切断」の項で論じるように、CLS が到着した場合、これらの接続シナリオはいずれも中断される。
1. 保留中の呼び出しキュー
保留中の RFC を何らかの形でキューイングする仕組みを実装することは不可欠である。このことは、典型的な LISTEN-CONNECT の順序を調べれば簡単にわかる。一方が LISTEN を発行し、他方が CONNECT を発行する。リモートの CONNECT から来る RFC が到着する前に LISTEN が発行されれば、何の問題もない。しかし、ネットワークの非同期的な性質により、この順序で事象が起こることは決して保証できない。呼び出しがキューイングされず、LISTEN の発行前に RFC が到着すれば、それは拒否される。後から到着すれば受け入れられる。したがって、極めてあいまいな状況になる。
無限のキュー領域がない限り、ユーザが一度も調べなかった古い RFC をキューから一掃する何らかの仕組みがあることが望ましい。明白だが非形式的な方法は、各 RFC がキューに入った時刻を記録しておき、ある任意の制限時間を超えた RFC をすべて定期的に拒否することである。どのような方式の文脈にもおそらく含めるべきもう 1 つの考えとして、ユーザがログアウトしたりクラッシュしたりしたときに、NCP が未完了のすべての接続または保留中の呼び出しに対して CLS を送るという方法がある。
本記述で用いる方式は、一見すると直観に反するように思えるかもしれないが、他の提案よりも現実的であると我々は考える。基本的に、CONNECT が発行されると、NCP はこのソケットが指定された外部ソケットと、そしてそのソケットとのみ通信したいと想定する。そのため、CLS を返送することで、一致しないすべての RFC を保留中の呼び出しキューから一掃する。同様に、接続が RFC-SENT 状態にある(CONNECT が発行されている)とき、一致しない RFC はすべて拒否される。LISTEN-ACCEPT または LISTEN-CLOSE の順序が実行された場合は、ユーザが将来これらの要求を受け入れたいと望む可能性を見込んで、残りの保留中の呼び出しはキューから取り除かれない。
後者の方法は恣意的であったり不必要に制限的であったりするように見えるかもしれないが、有能なプログラマ(すなわち、競合状態とネットワークの非同期的な性質に注意を払う者)を相手にしていると仮定すれば、この方法によって禁じられるシナリオを我々はまだ考え出せていない。もちろん、特定のサイトがどのような方式を選ぶかは実装に大きく依存する。我々は、上で述べた CONNECT による一掃方式において RFC が保持される期間と少なくとも同程度の桁の期間、RFC をキューイングする何らかの仕組みを用意することを提案する。
B. フロー制御
意味のあるデータは、接続が完全に開設されている(すなわち、2 つの RFC が交換され、切断が始まっていない)ときにのみ接続上を流れることができる。NCP は受信データ用のバッファを持ち、処理できるメッセージの大きさを示す何らかの意味のある量を(接続ごとに)通知できるものと仮定する。さらに、送信側はその大きさの通知に従って自らの送信を調整するものと仮定する。
接続が開設されると、1 つのセル('Their Size' と呼ぶ)がゼロに設定される。受信側は割り当て可能な領域の大きさを決め、その領域を指定した ALL メッセージを送る。送信側は割り当てられた領域の分だけ 'Their Size' を増やし、その後は長さが 'Their Size' 以下のメッセージを送信できるようになる。メッセージが送信されると、そのメッセージの長さが 'Their Size' から差し引かれる。受信側がさらにバッファ領域を割り当てると(例えば、ユーザがメッセージを受け取ってシステムバッファ領域の一部が解放されたとき)、解放されたビット数が ALL メッセージによって送信側に送られる。
したがって、'Their Size' が負になることは決してなく、'Their Size' がゼロに等しい場合には送信を行うことができない。
ALL メッセージで指定される長さは増分であり、受信バッファの絶対的な大きさではないことに注意されたい。これはフロー制御プロトコルの全二重的な性質によって必要となる。ALL メッセージの長さフィールドは 32 ビット長にでき(注:これは符号なし整数である)、それにより、万一望まれることがあれば、事実上無限の「ビットシンク」を実現する機能が提供される。
C. 切断
接続を開設するのに 2 つの RFC が必要であるのと同様に、接続を切断するには 2 つの CLS が必要である。切断はさまざまな状況で発生し、いくつかの目的を果たす。競合状態の分析を単純にするため、中止、拒否、受信側による終了、送信側による終了の 4 つの場合を区別する。
ユーザが CONNECT を発行し、その CONNECT が確認応答される前に CLOSE を発行した場合、ユーザは接続を「中止する(aborts)」という。典型的には、ユーザは確認応答を長く待った後に中止する。また、ユーザがクラッシュした場合には、そのシステムがユーザに代わって中止することもある。
ユーザが LISTEN を発行し、見込みのある呼び出し元について通知を受けた後に CLOSE を発行した場合、ユーザは接続を「拒否する(refuses)」という。特定のソケットからの呼び出しを待っているソケットに対する接続要求も、すべて拒否される。
接続が確立された後は、どちらの側も終了させることができる。必要とされる事象の順序から、受信側による CLOSE の試みは「要求(requests)」とみなすべきであり、送信側は常にできる限り速やかにそれに応じるべきであることがわかる。まだユーザに渡されていないデータや、ネットワーク上を流れ続けているデータは破棄される。送信側による CLOSE の要求は、すべてのデータ送信が完了し次第応じられる。
1. 中止
3 つの場合を区別できる。
- a) 最も単純な場合、我々が RFC を送り、その後に CLS を送る。相手側は CLS で応答し、接続の試みは終わる。
- b) ローカルプロセスが接続を中止するのと同時に、外部プロセスがその接続を受け入れる場合がある。この場合、外部プロセスは、ローカルプロセスが開設済みの接続を終了させていると解釈する。
- c) ローカルプロセスが接続を中止するのと同時に、外部プロセスがその接続を拒否する場合がある。この場合、外部プロセスは、ローカルプロセスが自らの拒否に確認応答していると解釈する。
2. 拒否
RFC を受信した後、ローカルホストは RFC または CLS で応答することもあれば、応答しないこともある。(ローカルホストがすでに自身の RFC を送っている場合などもある。)ローカルホストが CLS を送った場合、ローカルホストは接続要求を「拒否している(refusing)」という。
接続を切断するには CLS コマンドを交換することを必須とするので、ローカルホストは確認応答の CLS が返ってくるまでランデブーテーブルのエントリを維持する必要がある。
3. 送信側による終了
送信側のユーザが CLOSE システムコールを発行した場合、その NCP は直ちにそれを受け付けなければならないが、ローカルバッファ内のすべてのデータが外部ホストに渡されるまでは CLS コマンドを送出してはならない。したがって、CLS コマンドを送る前に 'buffer-empty' と 'RFNM-received' の両方を検査する必要がある。通常どおり、エントリを削除する前に CLS が確認応答されなければならない。
4. 受信側による終了
受信側のユーザが CLOSE システムコールを発行した場合、その NCP はそれを受け付け、直ちに CLS コマンドを送る。ただし、データがまだ到着することがあり、そのデータは破棄すべきである。送信側は CLS を受信したら、直ちにデータの流れを終了させるべきである。