目次 前項目 次項目

RMI ワイヤプロトコル


概要

RMI プロトコルは on-the-wire 形式のために他に2つのプロトコルを利用します。 Java オブジェクト直列化と HTTP です。オブジェクト直列化プロトコルは呼び出しと返り値の一体化(ストリーム化)に使用します。HTTP プロトコルはリモートメソッド呼び出しを "POST" し、かつ条件が許すならば返り値を取得するために使用します。 それぞれのプロトコルは別々の文法としてドキュメントが存在します。生成規則の非ターミナルシンボルは別のプロトコルの制御規則を参照します。(オブジェクト直列化または HTTP) プロトコルの境界を越える場合は、それ以後の生成規則はエンベッドされたプロトコルを使用します。

文法表記についての注意

RMI トランスポートプロトコル

RMI のワイヤ形式は Stream で表現されます。ここで採用している用語はクライアントからの観点を反映させたものです。Out は出力メッセージの参照を表し、In は入力メッセージの参照を表します。トランスポートヘッダの内容はオブジェクト直列化のフォーマットは行われません

Stream:
	Out
	In
RMI の入力と出力ストリームは対になっています。 各 Out ストリームは対応する In ストリームを持ちます。Out ストリームは文法的にはソケットの出力ストリームにマップします(クライアントの観点からは) In ストリームは (文法的には) は対応するソケットの入力ストリームと対を成します。出力と入力ストリームは対を作りますから、ヘッダー情報の中で入力ストリームで必要とするのはプロトコルを認識できたかどうかのアクノレッジのみです。それ以外のヘッダー情報(マジックナンバーやバージョン番号)はストリーム対のコンテキストで暗黙の了解が可能です。

出力ストリームの形式

RMI における出力ストリームは、トランスポート Header 情報とそれに続くMessages の並びから構成されます。 出力ストリームは HTTP プロトコルに呼び出しを埋め込んだものともいえます。

Out:
	Header Messages
	HttpMessage
Header:
	0x4a 0x52 0x4d 0x49 Version Protocol
Version:
	0x00 0x01
Protocol:
	StreamProtocol
	SingleOpProtocol
	MultiplexProtocol
StreamProtocol:
	0x4b
SingleOpProtocol:
	0x4c
MultiplexProtocol:
	0x4d
Messages:
	Message
	Messages Message
メッセージ は特定のプロトコル内で、 Protocol が指定する方法にしたがってラップされます。 SingleOpProtocol の場合は、Header に続く Message が一つしか無い場合があり、 Message の中にラップされるべき追加データが存在しないことがあります。SingleOpProtocol が使われるのは HTTP リクエストの中に呼び出しが埋め込まれるときであり、単一のリクエストと応答以上の相互作用はできません。

StreamProtocolMultiplexProtocol の場合は、サーバはバイトコード 0x4e で応答してプロトコルをサポートすることを知らせなければならず、そしてホスト名とポート番号を含んだ EndpointIdentifier で応答することによりサーバから見えるところは現在クライアントが使用中であることを知らせます。 クライアントはこの情報を用いて、セキュリティ上の理由でできない場合もありますが、自分のホスト名を知ることができます。 クライアントはその後、もう一個の EndpointIdentifier で応答する必要があり、応答の中には接続を受け付けるときのデフォルトの終点が含まれます。 MultiplexProtocol では、サーバはこの情報からクライアントを特定することが可能です。

StreamProtocol の場合は、エンドポイントのネゴシエーションの後に、 Messages がそれ以上のラッピングを行うことなしに出力ストリームへ送られます。 MultiplexProtocol の場合は、 RMI の多重プロトコルで解説されているようにソケット接続が多重化接続の具体的な接続として使用されます。 この多重化された接続上で開始された仮想接続は、次に説明される一連の Messages から構成されます。

出力タイプには、Call, Ping そして DgcAck の3つのタイプがあります。 Call はメソッド呼び出しをエンコードします。 Ping はトランスポートレベルのメッセージでありリモート仮想マシンが繋がっているかをテストします。 DGCAck はサーバの分散ガベージコレクタへ向けられたメッセージであり、サーバからの返り値に含まれるリモートオブジェクトがクライアントによって受け取られたことを示すアクノレッジ信号です。

Message:
	Call
	Ping
	DgcAck
Call:
	0x50 CallData
Ping:
	0x52
DgcAck:
	0x54 UniqueIdentifier	

入力ストリームの形式

現在入力メッセージには3つのタイプがあり、それぞれ ReturnData, HttpReturn そして PingAck の3種類です。 ReturnData は「通常の」RMI コールの結果です。 HttpReturn は HTTP プロトコルに埋め込まれた呼び出しに対する返り値です。 A PingAckPing メッセージに対するアクノレッジ応答です。

In:
	ProtocolAck Returns
	ProtocolNotSupported
	HttpReturn
ProtocolAck:
	0x4e
ProtocolNotSupported:
	0x4f
Returns:
	Return
	Returns Return
Return:
	ReturnData
	PingAck
ReturnData:
	0x51 ReturnValueopt
PingAck:
	0x53

RMI におけるオブジェクト直列化プロトコルの使用

RMI コールにおけるコールとリターンのデータは Java オブジェクト直列化プロトコルに従って整形されます。それぞれのメソッド呼び出しの CallDataObjectIdentifier (コールの対象)、Operation (呼び出されるメソッドを表す数値)、Hash (クライアントスタブとリモートオブジェクトが共通なスタブプロトコルを使うことを確認する数値)、そしてそれに続くArguments(無くてもよい)によって表現されます。

CallData:
	ObjectIdentifier Operation Hash Argumentsopt
ObjectIdentifier:
	ObjectNumber UniqueIdentifier
UniqueIdentifier:
	Number Time Count
Arguments:
	Value
	Arguments Value
Value:
	Object
	Primitive
RMI コールの ReturnValue はコールが正常終了したか例外を発生したかを示すリターンコード、リターン値にタグ付けする UniqueIdentifier (必要ならば DGCAck を送るために使用)、そしてこれに返り値 Value またはスローされた Exception が続きます。

ReturnValue:
	0x01 UniqueIdentifier Value
	0x02 UniqueIdentifier Exception
デフォルトの直列化では ObjectIdentifier, UniqueIdentifier, EndpointIdentifier は書き出されず、それぞれが自分自身の write メソッドを使います。(これはオブジェクト直列化が使う writeObject ではありません); それぞれのタイプの識別子の write メソッドはそれぞれのコンポーネントデータを順次出力ストリームへ追加します。

RMI における HTTP POST プロトコル

リモートメソッドをファイアウオールを通して呼び出しを行うために、RMI コールの幾つかは HTTP プロトコル、より具体的には HTTP POST を使用します。 ポストヘッダーで指定される URL は次のいずれかです。

	http://<host>:<port>/ 
	http://<host>:80/cgi-bin/java-rmi?forward=<port>
最初の URL は特定の hostport 上の RMI サーバと直接通信するために使われます。第二の URL 形式はサーバ上の "cgi" スクリプトが呼び出しを特定の port 上のサーバへ転送するために使用されます。

HttpPostHeader は POST リクエストのための標準 HTTP ヘッダーです。 HttpResponseHeader はポストへの標準 HTTP 応答です。応答のステータタスが200以外の場合は、Return が無いと判断されます。HTTP POST リクエストに埋め込まれる RMI コールは一つだけであることに注意してください。

HttpMessage:
	HttpPostHeader Header Message
HttpReturn:
	HttpResponseHeader Return
SingleOpProtocol だけが HttpMessageHeader に現れます。 HttpReturn はプロトコルのアクノレッジバイトを含みません。

RMI のアプリケーション固有の値

次の表は RMI で用いられるアプリケーション固有の値を表現する非ターミナルシンボルを列挙したものです。表はそれぞれのシンボルをそれぞれの持つ型に対応させています。各シンボルはそれが埋め込まれるプロトコルを使って整形されます。

Count			short
Exception		java.lang.Exception
Hash			long
Hostname		String
Number			int
Object			java.lang.Object
ObjectNumber		int
Operation		int
PortNumber		int
Primitive		byte, int, short, long...
Time			long

RMI の多重プロトコル

多重化の目的は、エンドポイントの一方だけが他の機能(例えば TCP 接続)を使って双方の接続を開くことができる環境に対して、2つのエンドポイントがそれぞれ相互に他端に対して多重の全二重接続を開くことができるモデルを提供することにあります。RMI はこの単純な多重化プロトコルを使って他の方法ではできない状況においても、クライアントが RMI サーバオブジェクトに接続するのを可能にします。 例えば、アプレット環境のセキュリティマネージャの中には、入ってくる接続を受信するためのサーバソケットの作成を禁止して、アプレットが RMI オブジェクトをエクスポートして直接ソケット接続からのリモートコールへのサービスすることををできないようにしています。 もしアプレット codebase ホストに対して通常のソケット接続をできるならば、その接続上で多重プロトコルを使い codebase ホストが、アプレットによりエクスポートされた RMI オブジェクトのメソッドを呼び出すことができます。 この章では多重プロトコルの形式と規則を説明します。

定義

この章では以後のプロトコルの説明で使用される用語を定義します。

エンドポイント とは多重プロトコルを使って接続されているユーザの一方を指します。

多重プロトコルはすでに存在する双方向の信頼できるバイトストリームの上位層になり、このバイトストリームはエンドポイントの片側が他方に対して開いたものです。現行の RMI の使用法ではこれは常に java.net.Socket オブジェクトを使って作られた TCP 接続です。この接続のことを具体的接続と呼びます。

多重プロトコルでは仮想接続機能を使うことができ、この接続は双方向の信頼できるバイトストリームであり、2つのエンドポイント間の特定のセッションを表現するものです。 2つのエンドポイント間の一つの具体的接続上の仮想接続のセットが多重接続を構成します。 多重プロトコルを使い、どちらのエンドポイントからも仮想接続のオープンとクローズが可能です。 仮想接続のあるエンドポイントに対しての状態は、具体的接続上でやり取りされる多重プロトコルの要素により定義されます。 この状態は接続のオープン、クローズに関連し、行き来する実際のデータと関連したフローコントロールを含みます。 特別ほかの説明が付加されなければ、接続という用語はこの章の以後の部分では 仮想接続の意味で用いられます。

ある多重接続の中の仮想接続は16ビット整数で特定され、これを 接続識別子と呼びます。したがって、一つの多重接続上には最大65,536の仮想接続が存在することになります。同時に使用できる仮想接続の数は実装によって制限されることがあります。

接続状態とフローコントロール

接続は種々の多重プロトコルにより定義された オペレーション により操作されます。 プロトコルで定義されたオペレーションには次の名前のものがあります: OPEN, CLOSE, CLOSEACK, REQUEST, そして TRANSMIT。 全てのオペレーションに関する正確な形式と規則の詳細はプロトコルの形式に説明されています。

OPEN, CLOSE, そして CLOSEACK オペレーションは接続の開いたり閉じたりし、REQUEST と TRANSMIT オペレーションは開いた接続上でフローコントロールメカニズムの制限下でのデータ伝送に使われます。

接続状態

仮想接続はエンドポイントが OPEN オペレーションをその接続に対して送り、その接続に対する OPEN オペレーションを受け取ると(そしてその後でクローズされていないならば)、その特定のエンドポイントに対して オープンした状態になります。 種々のオペレーションを次に説明します。

仮想接続はエンドポイントが接続に CLOSE オペレーションを送ったが、まだそれに続く CLOSE または CLOSEACK を受け取っていないときにそのエンドポイントに対して ペンディングクローズの状態にあります。

仮想接続は開かれなかったとき、あるいは CLOSE や CLOSEACK オペレーションを受け取ったときに(そしてそれ以後オープンされていないならば)、その特定のエンドポイントに対して クローズの状態にあります。

フローコントロール

多重プロトコルは一つの具体的接続上に平行して複数の仮想接続が存在できるように単純パケットフローコントロールメカニズムを使用します。フローコントロールメカニズムに要求される高レベルでの要求は、仮想接続の状態は独立であることです。つまり、一つの接続の状態は他の接続にたいして影響を及ぼしません。 例えば、接続に入ってくるデータを扱うバッファがフルになったとしても、これが他の接続のデータ伝送とかデータ処理を何ら妨げません。このことは一つの接続の進行状態は他の接続が終了してしまっても影響を受けないという特性実現のために重要です。RMI の再帰的なコールでは実際にこれが起こります。したがって、実際問題としては、接続の実装は常にいかなる時でも多重プロトコルデータ(プロトコル仕様を満たしていると仮定して)が具体的接続上に入ってくるのに備えている能力がなければなりません。

各エンドポイントはそれぞれの接続に関して2つの状態値を持ちます。 エンドポイントが何バイトのデータを要求し、そのうちの何バイトがまだ受け取っていないかを示す (入力要求カウント) と、もう一方のエンドポイントが何バイトのデータを要求し、その中でこちらのエンドポイントが何バイトを残しているかを示す (出力要求カウント) です。

一つのエンドポイントの出力要求カウントはもう一方のエンドポイントから REQUEST オペレーションを受けるたびに増加し、TRANSMIT オペレーションを送ると減少します。 一つのエンドポイントの入力要求カウントはそれが REQUEST オペレーションを送ると増加し、TRANSMIT オペレーションを受信すると減少します。どちらかの数値がマイナスになるとプロトコル違反です。

一つのエンドポイントが、ブロッキングの発生なしに現在扱えるバイト数の範囲を超えてて REQUEST オペレーションを送り入力要求カウントを限界を超えて増加させてしまうのはプロトコル違反になります。 しかし、接続されているユーザがデータを待っている状態では、入力要求カウントは確実にゼロ以上の値でなければなりません。 一つのエンドポイントが出力要求カウントを超えた TRANSMIT オペレーションを送るのはプロトコル違反です。 送出されるデータが、その接続のユーザが陽にフラッシュを要求するまで、バッファリングされていることがあります。 フラッシュ要求または、実装の出力バッファフルのためにデータが接続上に送出されるときは、接続上のユーザは十分に TRANSMIT オペレーションが進行するまでブロックされることがあります。

ここで概説した以外では、実装は適切と判断される範囲内で自由に REQUEST や TRANSMIT オペレーションを実行することが出来ます。例えば、エンドポイントは自分の受信バッファが空でなかったとしても接続にたいして追加データを要求することができます。

プロトコルの形式

多重プロトコルのバイトストリーム形式は、可変長レコードが隣接して繋がったものです。レコードの最初のバイトはオペレーションコードであり、そのレコードに対するオペレーションを明らかにし、それ以後の内容の形式を決定します。許されるオペレーションコードは次のとおりです。

	Value		Name
	-----		----

	0xE1		OPEN
	0xE2		CLOSE
	0xE3		CLOSEACK
	0xE4		REQUEST
	0xE5		TRANSMIT

レコードの最初のバイトが上に定義されたオペレーションコード以外のときはプロトコル違反になります。 次の章でそれぞれのオペレーションコードに対するレコード形式を説明します。

OPEN オペレーション

OPEN オペレーションの形式:

	size (bytes)		Name		Description
	------------		----		-----------

	1			opcode		オペレーションコード (OPEN)
	2			ID		接続識別子

エンドポイントは OPEN オペレーションを送って指定された接続を開きます。 もし ID が指示する接続がすでにオープンしていたり、送り側のエンドポイントに対してペンディングクローズの状態でこのこのコマンドを送るのはプロトコル違反です。 接続が開かれた状態では両側のエンドポイントでの入力と出力の要求カウントの状態は共にゼロになっています。

OPEN オペレーションの受信は他端のエンドポイントが指定の接続を開こうとしていることを示します。接続がオープンした状態では両側のエンドポイントでの入力と出力の要求カウントの状態は共にゼロになっています。

両側のエンドポイントでの識別子の衝突を防止するために、有効接続識別子のためのスペースは MSB (Most significat bit) の値によって2分されていてます。 それぞれのエンドポイントは高位ビットが特定の値を持っているときだけ接続を開くことが許されます。 具体的接続を開始しようとするエンドポイントは最高位ビットがセット (1)された識別子でのみ接続を開くことができ、他端のエンドポイントは最高位ビットがゼロに設定された識別子で接続を開かなければなりません。 例えば、サーバソケットを作成できない RMI アプレットが自分の codebase ホストに対して多重接続を開始しようとするときは、アプレットは仮想接続を識別子 0x8000-7FFF の範囲で開くことができ、サーバは識別子の範囲 0-0x7FFF の範囲で仮想接続を開くことができます。

CLOSE オペレーション

CLOSE オペレーションの形式:

	Size (bytes)		Name		Description
	------------		----		-----------

	1			opcode		オペレーションコード (OPEN)
	2			ID		接続識別子

エンドポイントは CLOSE オペレーションを送って指定の接続を閉じます。 もし、ID が指示する接続が現在閉じていたり、送信側に対してペンディングクローズになっているとプロトコル違反になります(もしこの接続に対して CLOSE オペレーションを送っていると受信側に対してペンディングクローズになっているかもしれません)。 CLOSE を送ると、その接続は送信側のエンドポイントに対してペンディングクローズ状態になります。従って、接続の他端から CLOSE または CLOSEACK を受け取ってからでないと再度接続を開くことはできません。

CLOSE オペレーションの受信は接続の他端がその接続を閉じたことを意味し、受信側にとっても接続は閉じられます。 受信側エンドポイントはこの接続に対してこれ以上の(再度オープンされない限り)オペレーションを行う必要はありませんが、実装の入力バッファにたまっているデータは接続のユーザへ渡さなければなりません。 もし接続がペンディングクローズではなく前もってオープンされているならば、受信側エンドポイントはその接続に対して CLOSEACK で応答する必要があります。

CLOSEACK オペレーション

CLOSEACK オペレーションのレコード形式:

	size (bytes)		Name		Description
	------------		----		-----------

	1			opcode		オペレーションコード (OPEN)
	2			ID		接続識別子

エンドポイントは受信側エンドポイントからの CLOSE を認識したことを知らせるために CLOSEACK オペレーションを送ります。 もし ID が指定する接続の受信側が、このオペレーションを受信したときにペンディングクローズの状態になっていない場合はプロトコル違反になります。

CLOSEACK オペレーションの受信は、その接続がペンディングクローズからクローズへ状態変化したことを示します。したがって、これ以後はその接続を再オープンすることができます。

REQUEST オペレーション

REQUEST オペレーションのレコード形式:
	size (bytes)		Name		Description
	------------		----		-----------

	1			opcode		オペレーションコード (OPEN)
	2			ID		接続識別子
	4			count		要求されたバイト数

エンドポイントは REQUEST オペレーションを送ってその接続の入力要求カウントを増加させます。 もし、ID が指定する接続が送信側のエンドポイントから見てオープンされていなければプロトコル違反になります。 エンドポイントの入力要求カウントは countが示す値だけ増加します。 count は符号付きの 32 bit 整数であり、もしこの値がゼロまたはマイナスになるのはプロトコル違反です。

REQUEST オペレーションの受信はその接続の出力要求カウントを countだけ増加させます。 もし受信側にとってその接続がペンディングクローズ状態であるときは、いかなる REQUEST オペレーションも無視されます。

TRANSMIT オペレーション

TRANSMIT オペレーションのレコード形式

	size (bytes)		Name		Description
	------------		----		-----------

	1			opcode		オペレーションコード (OPEN)
	2			ID		接続識別子
	4			count		伝送バイト数
	count			data		伝送データ

エンドポイントは TRANSMIT オペレーションにより指定の接続を介して実際のデータ伝送を行います。 もし、指定した接続が送信側のエンドポイントから見てクローズされているときはプロトコル違反になります。 エンドポイントの出力要求カウントは countの値だけ減少します。 count は符号付きの 32 bit 整数であり、送信側の値が TRANSMIT オペレーションによってゼロまたは負の値になるのはプロトコル違反です。

TRANSMIT オペレーションの受信は count バイトのデータがキューに追加され、接続から読める状態になったことを示します。受信側エンドポイントの入力要求カウントは count分だけ減少します。 もし、この結果入力要求カウントがゼロになり、かつ接続のユーザが更にデータを読む必要があるときは、エンドポイントは追加の REQUEST オペレーションで応答しなければなりません。 もし接続が受信側のエンドポイントから見てペンディングクローズならば、いかなる TRANSMIT オペレーションも無視されます。

プロトコル違反

上に説明したプロトコル違反が発生したとき、または具体的接続で通信エラーが発生したときは多重接続は shut down されます。実際の接続は終了し、全ての仮想接続も即時に閉じられます。仮想接続上ですでに読み込み可能になっていたデータは接続のユーザによって読みとり可能です。



目次 前項目 次項目

Copyright (C) 1996, 1997 Sun Microsystems, Inc. All rights reserved.