目次 | 前の項目 | 次の項目 | Java Remote Method Invocation |
多重化の目的は、エンドポイントの一方だけがほかの機能 (たとえば TCP 接続) を使って双方の接続を開くことができる環境において、2 つのエンドポイントが相互に、他端に対して多重の全二重接続を開くことができるモデルを提供することです。RMI により、この単純な多重化プロトコルを使って、ほかの方法では不可能な状況においても、クライアントが RMI サーバオブジェクトに接続できるようになります。たとえば、アプレット環境のセキュリティマネージャの中には、入ってくる接続を受信するためのサーバソケットの作成を禁止して、アプレットが RMI オブジェクトをエクスポートして直接ソケット接続からのリモート呼び出しをサービスできないようにするものがあります。アプレットが codebase ホストに対して通常のソケット接続を開くことができる場合には、その接続上で多重プロトコルを使うことにより、そのアプレットがエクスポートした RMI オブジェクトのメソッドを、codebase ホストが呼び出せるようになります。この章では、多重プロトコルの形式と規則を説明します。
この章では、後述のプロトコルの説明で使用される用語を定義します。エンドポイントとは、多重プロトコルを使って接続されているユーザの一方を指します。
多重プロトコルは、双方向の、信頼できる既存のバイトストリームの上位層になります。また、このバイトストリームは、エンドポイントの片側が他方に対して開いたものです。現在の RMI の使用法では、これは常に java.net.Socket オブジェクトを使って作られた TCP 接続です。この接続のことを具体的接続と呼びます。
多重プロトコルでは、仮想接続機能を使うことができます。仮想接続は、双方向の信頼できるバイトストリームであり、2 つのエンドポイント間の特定のセッションを表現するものです。2 つのエンドポイント間の 1 つの具体的接続上の仮想接続のセットが多重接続を構成します。多重プロトコルを使って、どちらのエンドポイントからでも仮想接続のオープンとクローズが行えます。仮想接続のあるエンドポイントに対する状態は、具体的接続上でやり取りされる多重プロトコルの要素により定義されます。この状態には、接続のオープンまたはクローズ、行き来する実際のデータ、および関連するフロー制御機構が含まれます。特にほかの説明がない場合、この章のこれ以降の部分では「接続」という用語は「仮想接続」の意味で用いられます。
ある多重接続の中の仮想接続は 16 ビット整数で特定され、これを接続識別子と呼びます。したがって、1 つの多重接続上には、最大 65,536 の仮想接続が存在することになります。同時に使用できる仮想接続の数は、実装によって制限されることがあります。
接続は、種々の多重プロトコルにより定義された「オペレーション」により操作されます。プロトコルで定義されたオペレーションには、OPEN、CLOSE、CLOSEACK、REQUEST、および TRANSMIT という名前のものがあります。すべてのオペレーションに関する正確な形式と規則の詳細は「10.6.3 プロトコルの形式」に説明されています。OPEN、CLOSE、および CLOSEACK オペレーションは、接続を開いたり閉じたりし、REQUEST と TRANSMIT オペレーションは、開いた接続上でフロー制御機構の制限下でのデータ伝送に使われます。
仮想接続は、エンドポイントが OPEN オペレーションをその接続に対して送り、その接続に対する OPEN オペレーションを受け取ると (ただし、そのあとにクローズされていない場合) 、その特定のエンドポイントに対してオープンした状態になります。 種々のオペレーションを次に説明します。仮想接続は、エンドポイントが接続に CLOSE オペレーションを送ったが、まだそれに続く CLOSE または CLOSEACK を受け取っていないときに、そのエンドポイントに対してペンディングクローズの状態にあります。
仮想接続は、開かれなかったとき、あるいは CLOSE や CLOSEACK オペレーションを受け取ったときに (ただし、それ以降にオープンされていない場合) 、その特定のエンドポイントに対してクローズの状態にあります。
多重プロトコルは、1 つの具体的接続上に、平行して複数の仮想接続が存在できるように単純パケットフロー制御機構を使用します。フロー制御機構における高度な要求として、仮想接続の状態はほかから独立していなければならないという要求があります。つまり、1 つの接続の状態は、ほかの接続に対して影響を及ぼしません。たとえば、接続に入ってくるデータを扱うバッファがいっぱいになったとしても、これがほかの接続のデータ伝送やデータ処理を妨げることはありません。このことは、1 つの接続の進行状態は、ほかの接続が終了しても影響を受けないという特性を実現するために重要です。RMI の再帰的な呼び出しでは、実際にこれが起こります。したがって、実際問題としては、接続の実装は常にいかなるときでも、具体的接続上に多重プロトコルデータ (プロトコル仕様を満たしていると仮定) が入ってくるのに備えている能力がなければなりません。各エンドポイントは、それぞれの接続に関して 2 つの状態値を持ちます。この状態値とは、エンドポイントが何バイトのデータを要求し、そのうちの何バイトをまだ受け取っていないかを示す (入力要求カウント) と、もう一方のエンドポイントが何バイトのデータを要求し、その中でこちらのエンドポイントが何バイトを残しているかを示す (出力要求カウント) です。
1 つのエンドポイントの出力要求カウントは、もう一方のエンドポイントから REQUEST オペレーションを受けるたびに増加し、TRANSMIT オペレーションを送ると減少します。1 つのエンドポイントの入力要求カウントは、それが REQUEST オペレーションを送ると増加し、TRANSMIT オペレーションを受信すると減少します。どちらかの数値がマイナスになるとプロトコル違反です。
1 つのエンドポイントが、入力要求カウントを、現時点でブロックされることなく処理できるバイト数以上に、増加させてしまうほど大きな REQUEST オペレーションを送ることはプロトコル違反です。しかし、接続しているユーザがデータを読み込むために待機している状態では、入力要求カウントは必ずゼロ以上の値でなければなりません。
1 つのエンドポイントが、出力要求カウントを超えた TRANSMIT オペレーションを送るのはプロトコル違反です。送出されるデータが、その接続のユーザが明示的にフラッシュを要求するまで、バッファリングされる可能性があります。明示的なフラッシュ要求、または実装の出力バッファがいっぱいであるために、その接続を経由してデータを送られなければならない場合は、接続上のユーザは TRANSMIT オペレーションが十分に進行するまでブロックされる可能性があります。
ここで説明した規則以外でも、適切と判断される範囲内で自由に REQUEST や TRANSMIT オペレーションを実行する実装が可能です。たとえば、エンドポイントは、自分の受信バッファが空でなかったとしても、接続に対して追加データを要求できます。
多重プロトコルのバイトストリーム形式は、可変長レコードが隣接して繋がったものです。レコードの最初のバイトは、オペレーションコードであり、そのレコードに対するオペレーションを明示し、それ以後の内容の形式を決定します。許されるオペレーションコードは次のとおりです。値 名前 0xE1 OPEN 0xE2 CLOSE 0xE3 CLOSEACK 0xE4 REQUEST 0xE5 TRANSMITレコードの最初のバイトが上に定義されたオペレーションコード以外のときは、プロトコル違反になります。 次の章では、それぞれのオペレーションコードに対するレコード形式を説明します。
OPEN オペレーションの形式を以下に示します。サイズ 名前 説明 1 (バイト) opcode オペレーションコード (OPEN) 2 (バイト) ID 接続識別子エンドポイントは、OPEN オペレーションを送ることによって、指定された接続を開きます。ID が指示する接続がすでにオープンしていたり、送り側のエンドポイントに対してペンディングクローズの状態でこのコマンドを送ったりするのは、プロトコル違反です。接続がオープンされたあとでは、その接続に対する入力および出力の要求カウントの状態は、両側のエンドポイントでゼロになっています。OPEN オペレーションの受信は、他端のエンドポイントが指定の接続を開こうとしていることを示します。接続がオープンされたあとでは、その接続に対する入力および出力の要求カウントの状態は、両側のエンドポイントでゼロになっています。
両側のエンドポイントでの識別子の衝突を防止するために、有効接続識別子のためのスペースは MSB (Most significat bit) の値によって 2 つに分かれています。それぞれのエンドポイントは、高位ビットが特定の値を持っている場合にだけ、接続を開くことが許されます。具体的接続を開始しようとするエンドポイントは、最高位ビットが設定された識別子でだけ接続を開くことができ、他端のエンドポイントは、最高位ビットがゼロに設定された識別子で接続を開かなければなりません。たとえば、サーバソケットを作成できない RMI アプレットが、自分の codebase ホストに対して多重接続を開始しようとする場合は、アプレットは仮想接続を識別子 0x8000-7FFF の範囲で開くことができ、サーバは識別子 0-0x7FFF の範囲で仮想接続を開くことができます。
CLOSE オペレーションの形式を以下に示します。サイズ 名前 説明 1 (バイト) opcode オペレーションコード (CLOSE) 2 (バイト) ID 接続識別子エンドポイントは、CLOSE オペレーションを送ることによって、指定の接続を閉じます。ID が指示する接続が現在閉じていたり、送信側に対してペンディングクローズになっているとプロトコル違反になります (この接続に対して CLOSE オペレーションを送っていると、受信側に対してペンディングクローズになっている可能性がある)。CLOSE を送ると、その接続は送信側のエンドポイントに対してペンディングクローズ状態になります。したがって、接続の他端から CLOSE または CLOSEACK を受け取ってからでないと、再度接続を開くことはできません。
CLOSE オペレーションの受信は、接続の他端がその接続を閉じたことを意味し、受信側にとっても接続は閉じられます。受信側エンドポイントは、この接続に対してこれ以上の (再度オープンされない限り) オペレーションを行う必要はありませんが、実装の入力バッファにたまっているデータは、接続のユーザへ渡さなければなりません。接続がペンディングクローズではなく前もってオープンされている場合は、受信側エンドポイントはその接続に対して CLOSEACK で応答する必要があります。
CLOSEACK オペレーションのレコード形式を以下に示します。サイズ 名前 説明 1 (バイト) opcode オペレーションコード (CLOSEACK) 2 (バイト) ID 接続識別子エンドポイントは、受信側エンドポイントからの CLOSE を認識したことを知らせるために CLOSEACK オペレーションを送ります。ID が指定する接続の受信側が、このオペレーションを受信したときにペンディングクローズの状態になっていない場合は、プロトコル違反になります。
CLOSEACK オペレーションの受信は、その接続の状態がペンディングクローズからクローズへ変化したことを示します。したがって、これ以後は、その接続を再オープンすることができます。
REQUEST オペレーションのレコード形式を以下に示します。サイズ 名前 説明 1 (バイト) opcode オペレーションコード (REQUEST) 2 (バイト) ID 接続識別子 4 (バイト) count 要求されたバイト数エンドポイントは、REQUEST オペレーションを送ることによって、その接続の入力要求カウントを増加させます。ID が指定する接続が、送信側のエンドポイントから見てオープンされていない場合は、プロトコル違反になります。エンドポイントの入力要求カウントは、count が示す値だけ増加します。count は、符号付きの 32 bit 整数であり、この値がゼロまたはマイナスになるのは、プロトコル違反です。
REQUEST オペレーションの受信は、その接続の出力要求カウントを count が示す値だけ増加させます。受信側にとってその接続がペンディングクローズ状態であるときは、REQUEST オペレーションはすべて無視されます。
TRANSMIT オペレーションのレコード形式を以下に示します。サイズ 名前 説明 1 (バイト) opcode オペレーションコード (TRANSMIT) 2 (バイト) ID 接続識別子 4 (バイト) count 伝送バイト数 count data 伝送のデータエンドポイントは、TRANSMIT オペレーションにより、指定の接続を介して実際のデータ伝送を行います。指定した接続が、送信側のエンドポイントから見てクローズされている場合は、プロトコル違反になります。エンドポイントの出力要求カウントは、count の値だけ減少します。count は、符号付きの 32 bit 整数であり、送信側の値が TRANSMIT オペレーションによって、ゼロまたは負の値になるのはプロトコル違反です。
TRANSMIT オペレーションの受信は、count バイトのデータがキューに追加され、接続から読める状態になったことを示します。受信側エンドポイントの入力要求カウントは count の値だけ減少します。この結果、入力要求カウントがゼロになり、かつ接続のユーザがさらにデータを読み込む必要がある場合は、エンドポイントは追加の REQUEST オペレーションで応答しなければなりません。接続が受信側のエンドポイントから見てペンディングクローズになっている場合、TRANSMIT オペレーションはすべて無視されます。
上述したプロトコル違反が発生した場合、または具体的接続で通信エラーが発生した場合は、多重接続はシャットダウンされます。実際の接続が終了し、全ての仮想接続も即時に閉じられます。仮想接続上ですでに読み込み可能になっていたデータは、接続のユーザによって読み取り可能です。