この章では Sun RPC としても知られている TI-RPC について概要を説明します。RPC に初めて接するユーザーに役立つ情報を記載しています (用語の定義は、用語集を参照してください)。
TI-RPC はクライアントサーバーをベースにした分散型アプリケーションを構築するための強力な技術です。従来のローカルの手続き呼び出しの概念を拡張し、呼び出された手続きが呼び出す手続きと同じアドレス空間に存在する必要がないようにしています。2 つのプロセスが同じシステム上に存在することもあり、また、ネットワーク上で接続された異なるシステム上に存在する場合もあります。
RPC を使用すると、分散型アプリケーションを作成するプログラマはネットワークとの詳細なインタフェースを意識する必要がありません。 RPC はトランスポート層に依存しないため、データ通信の物理的および論理的な機構からアプリケーションを切り離して作成することができ、したがって、アプリケーションはさまざまなトランスポートを使用できます。
RPC は関数呼び出しに類似したものです。RPC を実行すると、呼び出し時の引数が遠隔手続きに渡され、呼び出し側は遠隔手続きからの応答を待ちます。
図 2-1 に、2 つのネットワーク上のシステム間でのRPC 呼び出し時に実行される動作のフローを示します。クライアントは、サーバーに要求を送信して応答を待つ手続き呼び出しを行います。応答が受信されるかまたはタイムアウトになるまで、スレッドの実行は停止されます。要求が届くと、サーバーは要求されたサービスを実行するディスパッチルーチンを呼び出し、その結果をクライアントに返します。RPC 呼び出しが終了すると、クライアントはプログラムの続きを実行します。
RPC はネットワークアプリケーションをサポートします。TI-RPC は TCP/IP のようなネットワーク機構上で実行されます。その他の標準の RPC としては、OSF DCE (Apollo の NCS システムをベースにしています)、Xerox Courier、Netwise があります。
特定の RPC を実装する場合には次の点に注意が必要です。
パラメータと結果が渡される方法
結合が行われる方法
トランスポートプロトコルが使用される方法
呼び出しセマンティクス
使用されるデータ表現
TI-RPC では 1 つのパラメータをクライアントからサーバーに渡すことができます。複数のパラメータが必要なときは、1 つの要素とみなされる 1 つの構造体に含めて渡されます。サーバーからクライアントに渡される情報は、関数の戻り値として渡されます。サーバーからクライアントにパラメータリストを通して情報を戻すことはできません。
クライアントは、サービスの使用方法を知っていなければなりません。サーバーのホスト名を知ることと、実際のサーバーのプロセスに接続することが必要です。各ホストでは、rpcbind と呼ばれるサービスが RPC サービスを管理します。TI-RPC は hosts ファイルと ipnodes ファイル、NIS+、DNS などのホストネームサービスを使用してホストの位置を確認します。
トランスポートプロトコルは、クライアントとサーバーとの間で呼び出しおよび返答メッセージがどのように送信されるかを指定します。TS-RPC はトランスポートプロトコルとして TCP と UDP を使用しますが、現在の TI-RPC バージョンはトランスポートに依存しません。つまり、TI-RPC は任意のトランスポートプロトコルで動作します。
呼び出しセマンティクスは、遠隔手続きの実行に関し、特にその手続きが何回実行されたかについてクライアントが仮定することに関係があります。これはエラー条件を扱う場合に重要です。この場合、「1 回」、「多くても 1 回」、「少なくとも 1 回」の 3 つのセマンティクスがあります。ONC+ では「少なくとも 1 回」のセマンティクスを提供します。遠隔で呼び出される手順は一貫しています。つまり、たとえ数回にわたって呼び出されても同じ結果を返す必要があります。
データ表現とは、プロセス間でパラメータと結果が渡されるときに使用されるフォーマットのことです。さまざまなシステムアーキテクチャ上で RPC が機能するためには、標準データ形式が必要です。TI-RPC では、標準データ形式として外部データ表現 (XDR: external Data Representation) を使用します。XDR はマシンに依存しないデータ形式と符号化のためのプロトコルです。TI-RPC では、XDR を使用することによって、各ホストのバイト順序や構造体の配置方法に影響されることなく、任意のデータ構造を扱うことができます。XDR の詳細については、付録 C 「XDR プロトコル仕様」 および 付録 A 「XDR テクニカルノート」 を参照してください。
プログラム番号
バージョン番号
手続き番号
プログラム番号とは、関連する遠隔手続きがグループ化された 1 つのプログラムを示します。プログラム内の各手続きは固有の手続き番号を持っています。
プログラムは 1 つまたは複数のバージョンを持つ場合があります。各バージョンは遠隔で呼び出せる手続きの集まりです。バージョン番号を利用することにより、1 つの RPC プロトコルの複数のバージョンを同時に使用できます。
各バージョンには遠隔で呼び出せる多くの手続きが含まれます。各手続きは、手続き番号を持っています。
「プログラムと手続き番号」では、値の範囲と意味を示し、プログラム番号を RPC プログラムに割り当てる方法を説明しています。RPC サービス名とプログラム番号との対応リストは、rpc ネットワークデータベースの /etc/rpc にあります。
RPC が提供するサービスには、さまざまなレベルのアプリケーションインタフェースがあります。レベルごとに制御の度合いが異なるため、インタフェースのコーディング量との兼ね合いで適当なレベルを使用してください。この節では、制御の度合いとプログラムの複雑さの順に、各レベルで利用できるルーチンについて要約します。
単純インタフェースは、使用するトランスポートタイプだけを指定して、他のマシン上のルーチンを遠隔手続き呼び出しにより実行します。ほとんどのアプリケーションで、このレベルのルーチンを使用します。この説明とコード例は、「単純インタフェース」を参照してください。
表 2-1 RPC ルーチン - 単純レベル
ルーチン |
説明 |
---|---|
手続きを RPC プログラムとして、指定したタイプのトランスポートすべてに登録する |
|
指定した遠隔ホスト上の指定した手続きを遠隔呼び出しする |
|
指定したタイプのトランスポートすべてに呼び出しメッセージをブロードキャストする |
標準インタフェースはトップレベル、中間レベル、エキスパートレベル、ボトムレベルの 4 つのレベルに分けられます。開発者はこれらのインタフェースを使用して、トランスポートの選択、エラーへの応答または要求の再送まで待つ時間の指定などのパラメータをかなり詳細に制御できます。
トップレベルのインタフェースも簡単に使用できますが、RPC 呼び出しを行う前にクライアントハンドルを作成し、RPC 呼び出しを受ける前にサーバーハンドルを作成しなければなりません。アプリケーションをすべてのトランスポート上で実行したい場合は、このインタフェースを使用してください。このルーチンの使用方法とコード例は、「トップレベルのインタフェース」を参照してください。
表 2-2 RPC ルーチン - トップレベル
ルーチン |
説明 |
---|---|
汎用のクライアント作成ルーチン。このルーチンは、サーバーの位置と、使用するトランスポートのタイプを指定して呼び出す |
|
clnt_create() に似ているが、クライアントの作成を試みる間、各トランスポートタイプに許される最長時間を指定できる |
|
指定したタイプのトランスポートすべてに対しサーバーハンドルを作成する。このルーチンは、使用するディスパッチ関数を svc_create() に指定して呼び出す |
|
要求をサーバーに送信するための手続きをクライアント側から呼び出す |
RPC の中間レベルのインタフェースを使用すると、通信を詳細に制御できます。このような下位レベルのインタフェースを使用すると、プログラムは複雑になりますが、効率はよくなります。中間レベルでは特定のトランスポートを指定できます。このルーチンの使用方法とコード例は、「中間レベルのインタフェース」を参照してください。
表 2-3 RPC ルーチン - 中間レベル
ルーチン |
説明 |
---|---|
指定したトランスポートに対するクライアントハンドルを作成する |
|
clnt_tp_create() に似ているが、許される最長時間を指定できる |
|
指定したトランスポートに対するサーバーハンドルを作成する |
|
要求をサーバーに送信するための手続きをクライアント側から呼び出す |
エキスパートレベルには、トランスポートに関連するパラメータを指定するさまざまなルーチンがあります。このルーチンの使用方法とコード例は、「エキスパートレベルのインタフェース」を参照してください。
表 2-4 RPC ルーチン - エキスパートレベル
ルーチン |
説明 |
---|---|
指定したトランスポートに対するクライアントハンドルを作成する |
|
指定したトランスポートに対するサーバーハンドルを作成する |
|
rpcb_set() で作成したマップを削除する |
|
rpcbind デーモンを呼び出して、指定した RPC サービスのトランスポートアドレスを取り出す |
|
指定したプログラム番号とバージョン番号のペアを、指定したディスパッチルーチンに関連付ける |
|
svc_reg() で設定した関連付けを解除する |
|
要求をサーバーに送信するための手続きをクライアント側から呼び出す |
ボトムレベルには、トランスポートを完全に制御することができるルーチンがあります。これらのルーチンについては、「ボトムレベルのインタフェース」を参照してください。
表 2-5 RPC ルーチン - ボトムレベル
ルーチン |
説明 |
---|---|
非接続型トランスポートを使用して、指定した遠隔プログラムに対する RPC クライアントハンドルを作成する |
|
非接続型トランスポートを使用して、RPC サーバーハンドルを作成する |
|
接続型トランスポートを使用して、指定した遠隔プログラムに対する RPC クライアントハンドルを作成する |
|
接続型トランスポートを使用して、RPC サーバーハンドルを作成する |
|
clnt_call() |
特定のトランスポートまたはトランスポートタイプで実行されるプログラムを書くことができます。あるいは、システムが選択するトランスポート、またはユーザーが選択するトランスポート上で実行されるプログラムを書くこともできます。ネットワークの選択では、/etc/netconfig データベースと環境変数 NETPATH を使用します。これにより希望するトランスポートを指定したり、また可能であればアプリケーションがそれを使用できます。指定したトランスポートが不適当な場合、アプリケーションは自動的に適切な機能を持つ他のトランスポートを使用しようとします。
/etc/netconfig には、ホストで使用できるトランスポートが記載されていて、タイプによって識別されます。NETPATH はオプションで、ユーザーはこれを使用してトランスポートを指定したり、/etc/netconfig にあるリストからトランスポートを選択したりできます。NETPATH を設定するとユーザーは、アプリケーションが利用できるトランスポートを試みる順序を指定できます。NETPATH を設定しないと、システムはデフォルトで /etc/netconfig に指定されているすべての選択可能なトランスポート (visible (可視) トランスポート) について、ファイルに現れる順番で選択を試みます。
ネットワーク選択についての詳細は、『Transport Interfaces Programming Guide』または getnetconfig(3NSL) と netconfig(4) のマニュアルページを参照してください。
RPC では、選択可能なトランスポートを次のタイプに分類します。
表 2-6 nettype パラメータ
値 |
説明 |
---|---|
netpath と同じ |
|
/etc/netconfig ファイルのエントリのうち、可視フラグ (v フラグ) の付いたトランスポートが使用される |
|
visible と同じ。ただし、接続型トランスポートに限定される。/etc/netconfig ファイルに記載された順に選択される |
|
visible と同じ。ただし、非接続型トランスポートに限定される |
|
接続型トランスポートが、NETPATH で設定された順に使用される |
|
非接続型トランスポートが、NETPATH で設定された順に使用される |
|
インターネット・ユーザーデータグラム・プロトコル (UDP) が指定される |
|
インターネット・トランスミッション・コントロール・プロトコル (TCP) が指定される |
RPC サービスは、接続型と非接続型の両方のトランスポートでサポートされています。トランスポート選択は、アプリケーションの性質で決まります。
アプリケーションが次のすべてに当てはまる場合は、非接続型トランスポートの方が適当です。
手続きの呼び出しによってサーバー内部の状態や関連データが変更されない
引数と戻り値のサイズがトランスポートのパケットサイズより小さい
サーバーは非常に多くのクライアントを扱う必要がある。非接続型サーバーは各クライアントの状態データを保持する必要がないため、本質的に数多くのクライアントを処理することができる。これに対して、接続型サーバーではオープンしているクライアント接続すべての状態データを保持するため、処理できるクライアント数はホストの資源によって制限される
アプリケーションが次のどれかに当てはまる場合は、接続型トランスポートの方が適当です。
非接続型トランスポートと比較して、アプリケーションで接続の確立により多くの手間をかけることができる
手続きの呼び出しによってサーバー内部の状態や関連データが変更される可能性がある
引数または戻り値のサイズがデータグラムパケットの最大サイズより大きい
各トランスポートには固有の変換ルーチンがあり、汎用ネットワークアドレス (トランスポートアドレスを文字列で表現したもの) とローカルアドレスとの相互変換を行います。RPC システム内 (例えば、rpcbind とクライアントの間) では、汎用アドレスが使用されます。各トランスポートには、名前からアドレスへの変換ルーチンの入った実行時リンクライブラリがあります。表 2-7 に、主な変換ルーチンを示します。
上の各ルーチンについての詳細は、netdir(3NSL) のマニュアルページと『Transport Interfaces Programming Guide』を参照してください。どのルーチンの場合も、netconfig 構造体が名前からアドレスへの変換のコンテキストを提供していることに注意してください。
表 2-7 名前からアドレスへの変換ルーチン
netdir_getbyname() |
ホストとサービスのペア(たとえば、server1、rpcbind) と netconfig 構造体から、netbuf アドレスのセットに変換する。netbuf は TLI 構造体で、実行時にトランスポート固有のアドレスが入る netbuf アドレスと netconfig 構造体から、ホストとサービスのペアに変換する |
uaddr2taddr() |
汎用アドレスと netconfig 構造体から、netbuf アドレスに変換する |
taddr2uaddr () |
netbuf アドレスと netconfig 構造体から、汎用アドレスに変換する |
トランスポートサービスにはアドレスルックアップサービスは含まれていません。トランスポートサービスはネットワーク上のメッセージ転送だけを行います。クライアントプログラムは、使用するサーバープログラムのアドレスを知る必要があります。旧バージョンの SunOS では、portmap デーモンがそのサービスを実行していました。現バージョンでは rpcbind デーモンを使用します。
RPC では、ネットワークアドレスの構造を考慮する必要がありません。RPC では、NULL で終わる ASCII 文字列で指定される汎用アドレスを使用するためです。RPC はトランスポート固有の変換ルーチンを使用して、汎用アドレスをローカルトランスポートアドレスに変換します。変換ルーチンについての詳細は、netdir(3NSL) と rpcbind(3NSL) のマニュアルページを参照してください。
rpcbind の機能を次に示します。
登録リスト全体を取り出す
クライアントのための遠隔呼び出しを実行する
時刻を返す
rpcbind が RPC サービスをアドレスにマップするので、rpcbind 自体のアドレスはその利用者に知られていなければなりません。全トランスポートの名前からアドレスへの変換ルーチンが、トランスポートが使用する各タイプのためのアドレスを保有している必要があります。たとえば、インターネットドメインでは、TCPでも UDP でも rpcbind のポート番号は 111 です。rpcbind は、起動されるとホストがサポートしている全トランスポートに自分のアドレスを登録します。RPC サービスのうち rpcbind だけは、前もってアドレスが知られていなければなりません。
rpcbind は、ホストがサポートしている全トランスポートに RPC サービスのアドレスを登録して、クライアントがそれらを使用できるようにします。各サービスは、rpcbind デーモンでアドレスを登録し、クライアントから利用できるようになります。そこで、サービスのアドレスが rpcinfo(1M) と rpcbind(3NSL) のマニュアルページで指定されているライブラリルーチンを使用するプログラムとで利用可能になります。クライアントやサーバーからは RPC サービスのネットワークアドレスを知ることはできません。
クライアントプログラムとサーバープログラム、および、クライアントホストとサーバーホストとは通常別のものですが、同じであってもかまいません。サーバープログラムもまたクライアントプログラムになることができます。あるサーバーが別の rpcbind サーバーを呼び出す場合は、クライアントとして呼び出したことになります。
クライアントが遠隔プログラムのアドレスを調べるには、ホストの rpcbind デーモンに RPC メッセージを送信します。サービスがホスト上にあれば、デーモンは RPC 応答メッセージにアドレスを入れて返します。そこで、クライアントプログラムは RPC メッセージをサーバーのアドレスに送ることができます。(クライアントプログラムから rpcbind を頻繁に呼び出さなくて済むように、最後に呼び出した遠隔プログラムのネットワークアドレスを保存しておきます)。
rpcbind の RPCBPROC_CALLIT 手続きを使用すると、クライアントはサーバーのアドレスがわからなくても遠隔手続きを呼び出すことができます。クライアントは目的の手続きのプログラム番号、バージョン番号、手続き番号、引数を RPC 呼び出しメッセージで引き渡します。rpcbind は、アドレスマップから目的の手続きのアドレスを探し出し、RPC 呼び出しメッセージにクライアントから受け取った引数を入れて、その手続きに送信します。
目的の手続きから結果が返されると、RPCBPROC_CALLIT はクライアントプログラムにその結果を引き渡します。そのとき、目的の手続きの汎用アドレスも同時に渡されますので、次からはクライアントが直接その手続きを呼び出すことができます。
RPC ライブラリは rpcbind の全手続きのインタフェースを提供します。RPC ライブラリの手続きには、クライアントとサーバーのプログラムのために rpcbind を自動的に呼び出すものもあります。詳細については、付録 B 「RPC プロトコルおよび言語の仕様」 を参照してください。
rpcinfo は、rpcbind で登録した RPC の最新情報を取り出すユーティリティです。rpcbind または portmap ユーティリティと共に rpcinfo を使用して、あるホストに登録されたすべての RPC サービスの汎用アドレスとトランスポートを知ることができます。指定したホスト上で指定したプログラムの特定バージョンを呼び出して、応答が返ったかどうかを調べることができます。詳細については、rpcinfo(1M) のマニュアルページを参照してください。