ONC+ 開発ガイド

第 2 章 TI-RPC 入門

この章では Sun RPC としても知られている TI-RPC について概要を説明します。RPC に初めて接するユーザーに役立つ情報を記載しています。この章で使用する用語の定義については、用語集を参照してください。

この章では、次のトピックについて説明します。

TI-RPC の概要

TI-RPC はクライアントサーバーをベースにした分散型アプリケーションを構築するための強力な技術です。従来のローカルの手続き呼び出しの概念を拡張し、呼び出された手続きが呼び出す手続きと同じアドレス空間に存在する必要がないようにしています。2 つのプロセスが同じシステム上に存在することもあり、また、ネットワーク上で接続された異なるシステム上に存在する場合もあります。

RPC を使用すると、分散型アプリケーションを作成するプログラマはネットワークとの詳細なインタフェースを意識する必要がありません。 RPC はトランスポート層に依存しないため、データ通信の物理的および論理的な機構からアプリケーションを切り離して作成することができ、したがって、アプリケーションはさまざまなトランスポートを使用できます。

図 2–1 リモートプロシージャ呼び出しの動作

Graphic

RPC は関数呼び出しに類似したものです。RPC を実行すると、呼び出し時の引数がリモートプロシージャに渡され、呼び出し側はリモートプロシージャからの応答を待ちます。

図 2–1に、2 つのネットワーク上のシステム間でのRPC 呼び出し時に実行される動作のフローを示します。クライアントは、サーバーに要求を送信して応答を待つ手続き呼び出しを行います。応答が受信されるかまたはタイムアウトになるまで、スレッドの実行は停止されます。要求が届くと、サーバーは要求されたサービスを実行するディスパッチルーチンを呼び出し、その結果をクライアントに返します。RPC 呼び出しが終了すると、クライアントはプログラムの続きを実行します。

RPC はネットワークアプリケーションをサポートします。TI-RPC は TCP/IP のようなネットワーク機構上で実行されます。その他の標準の RPC としては、OSF DCE (Apollo の NCS システムをベースにしています)、Xerox Courier、Netwise があります。

TI-RPC の問題

特定の 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 はマシンに依存しないデータ形式と符号化のためのプロトコルです。XDR を使用することによって、TI-RPC では、各ホストのバイト順序や構造体の配置方法に影響されることなく、任意のデータ構造を扱うことができます。XDR の詳細については、 付録 A 「XDR テクニカルノート」および付録 C 「XDR プロトコル仕様」 を参照してください。

プログラム、バージョン、手続き番号

リモートプロシージャは次の 3 つの要素によって一意に識別されます。

プログラム番号とは、関連するリモートプロシージャがグループ化された 1 つのプログラムを示します。プログラム内の各手続きは固有の手続き番号を持っています。

プログラムは 1 つまたは複数のバージョンを持つ場合があります。各バージョンはリモートで呼び出せる手続きの集まりです。バージョン番号を利用することにより、1 つの RPC プロトコルの複数のバージョンを同時に使用できます。

各バージョンにはリモートで呼び出せる多くの手続きが含まれます。各手続きは、手続き番号を持っています。

プログラムと手続き番号では、値の範囲と意味を示し、プログラム番号を RPC プログラムに割り当てる方法を説明しています。RPC サービス名とプログラム番号との対応リストは、RPC ネットワークデータベースの /etc/rpc にあります。

インタフェースルーチンの概要

RPC が提供するサービスには、さまざまなレベルのアプリケーションインタフェースがあります。レベルごとに制御の度合いが異なるため、インタフェースのコーディング量との兼ね合いで適当なレベルを使用してください。この節では、制御の度合いとプログラムの複雑さの順に、各レベルで利用できるルーチンについて要約します。

単純インタフェースのルーチン

単純インタフェースは、使用するトランスポートタイプだけを指定して、他のマシン上のルーチンをリモートプロシージャ呼び出しにより実行します。ほとんどのアプリケーションで、このレベルのルーチンを使用します。この説明とコード例は、単純インタフェースを参照してください。

表 2–1 RPC ルーチン - 単純レベル

ルーチン 

機能 

rpc_reg ()

手続きを RPC プログラムとして、指定したタイプのトランスポートすべてに登録する 

rpc_call ()

指定したリモートホスト上の指定した手続きをリモート呼び出しする 

rpc_broadcast ()

指定したタイプのトランスポートすべてに呼び出しメッセージをブロードキャストする 

標準インタフェースのルーチン

標準インタフェースはトップレベル、中間レベル、エキスパートレベル、ボトムレベルの 4 つのレベルに分けられます。プログラマはこれらのインタフェースを使用して、トランスポートの選択、エラーへの応答または要求の再送まで待つ時間の指定などのパラメータをかなり詳細に制御できます。

トップレベルのルーチン

トップレベルのインタフェースも簡単に使用できますが、RPC 呼び出しを行う前にクライアントハンドルを作成し、RPC 呼び出しを受ける前にサーバーハンドルを作成しなければなりません。アプリケーションをすべてのトランスポート上で実行したい場合は、このインタフェースを使用してください。このルーチンの使用方法とコード例は、トップレベルのインタフェースを参照してください。

表 2–2 RPC ルーチン—トップレベル

ルーチン 

説明 

clnt_create ()

汎用のクライアント作成ルーチン。このルーチンは、サーバーの位置と、使用するトランスポートのタイプを指定して呼び出す 

clnt_create_timed ()

clnt_create() に似ているが、クライアントの作成を試みる間、各トランスポートタイプに許される最長時間を指定できる

svc_create ()

指定したタイプのトランスポートすべてに対しサーバーハンドルを作成する。このルーチンは、使用するディスパッチ関数を svc_create() に指定して呼び出す

clnt_call() ()

要求をサーバーに送信するための手続きをクライアント側から呼び出す 

中間レベルのインタフェース

RPC の中間レベルのインタフェースを使用すると、通信を詳細に制御できます。このような下位レベルのインタフェースを使用すると、プログラムは複雑になりますが、効率はよくなります。中間レベルでは特定のトランスポートを指定できます。このルーチンの使用方法とコード例は、中間レベルのインタフェースを参照してください。

表 2–3 RPC ルーチン—中間レベル

ルーチン 

説明 

clnt_tp_create ()

指定したトランスポートに対するクライアントハンドルを作成する 

clnt_tp_create_timed ()

clnt_tp_create() に似ているが、許される最長時間を指定できる

svc_tp_create ()

指定したトランスポートに対するサーバーハンドルを作成する 

clnt_call() ()

要求をサーバーに送信するための手続きをクライアント側から呼び出す 

エキスパートレベルのインタフェース

エキスパートレベルには、トランスポートに関連するパラメータを指定するさまざまなルーチンがあります。このルーチンの使用方法とコード例は、エキスパートレベルのインタフェースを参照してください。

表 2–4 RPC ルーチン—エキスパートレベル

ルーチン 

説明 

clnt_tli_create ()

指定したトランスポートに対するクライアントハンドルを作成する 

svc_tli_create ()

指定したトランスポートに対するサーバーハンドルを作成する 

rpcb_set ()

rpcbind デーモンを呼び出して、RPC サービスとネットワークアドレスとのマップを作成する

rpcb_unset ()

rpcb_set() で作成したマップを削除する

rpcb_getaddr ()

rpcbind() デーモンを呼び出して、指定した RPC サービスのトランスポートアドレスを取り出す

svc_reg ()

指定したプログラム番号とバージョン番号のペアを、指定したディスパッチルーチンに関連付ける 

svc_unreg ()

svc_reg() で設定した関連付けを解除する

clnt_call() ()

要求をサーバーに送信するための手続きをクライアント側から呼び出す 

ボトムレベルのインタフェース

ボトムレベルには、トランスポートを完全に制御することができるルーチンがあります。これらのルーチンについては、ボトムレベルのインタフェースを参照してください。

表 2–5 RPC ルーチン—ボトムレベル

ルーチン 

説明 

clnt_dg_create ()

非接続型トランスポートを使用して、指定したリモートプログラムに対する RPC クライアントハンドルを作成する 

svc_dg_create ()

非接続型トランスポートを使用して、RPC サーバーハンドルを作成する 

clnt_vc_create ()

接続型トランスポートを使用して、指定したリモートプログラムに対する RPC クライアントハンドルを作成する 

svc_vc_create ()

接続型トランスポートを使用して、RPC サーバーハンドルを作成する 

clnt_call() ()

要求をサーバーに送信するための手続きをクライアント側から呼び出す 

ネットワーク選択

特定のトランスポートまたはトランスポートタイプで実行されるプログラムを書くことができます。あるいは、システムが選択するトランスポート、またはユーザーが選択するトランスポート上で実行されるプログラムを書くこともできます。ネットワークの選択では、/etc/netconfig データベースと環境変数 NETPATH を使用します。これにより希望するトランスポートを指定できます。それは、可能であればアプリケーションによって使用されます。指定したトランスポートが不適当な場合、アプリケーションは自動的に適切な機能を持つ他のトランスポートを使用しようとします。

/etc/netconfig には、ホストで使用できるトランスポートが記載されていて、タイプによって識別されます。NETPATH はオプションで、ユーザーはこれを使用してトランスポートを指定したり、/etc/netconfig にあるリストからトランスポートを選択したりできます。NETPATH を設定するとユーザーは、アプリケーションが利用できるトランスポートを試みる順序を指定できます。NETPATH を設定しないと、システムはデフォルトで /etc/netconfig に指定されているすべての選択可能なトランスポート (visible (可視) トランスポート) について、ファイルに現れる順番で選択を試みます。

ネットワーク選択についての詳細は、getnetconfig(3NSL) または netconfig(4) のマニュアルページを参照してください。

RPC では、選択可能なトランスポートを次のタイプに分類します。

表 2–6 nettype パラメータ

値 

意味 

NULL

netpath と同じ

visible

/etc/netconfig ファイルのエントリのうち、可視フラグ (v フラグ) の付いたトランスポートが使用される

circuit_v

visible と同じ。ただし、接続型トランスポートに限定される。/etc/netconfig ファイルに記載された順に選択される

datagram_v

visible と同じ。ただし、非接続型トランスポートに限定される

circuit_n

接続型トランスポートが、NETPATH で設定された順に使用される

datagram_n

非接続型トランスポートが、NETPATH で設定された順に使用される

udp

インターネット・ユーザーデータグラム・プロトコル (UDP) が指定される 

tcp

インターネット・トランスミッション・コントロール・プロトコル (TCP) が指定される 

トランスポート選択

RPC サービスは、接続型と非接続型の両方のトランスポートでサポートされています。トランスポート選択は、アプリケーションの性質で決まります。

アプリケーションが次のすべてに当てはまる場合は、非接続型トランスポートの方が適当です。

アプリケーションが次のどれかに当てはまる場合は、接続型トランスポートの方が適当です。

名前からアドレスへの変換

各トランスポートには固有の変換ルーチンがあり、汎用ネットワークアドレス (トランスポートアドレスを文字列で表現したもの) とローカルアドレスとの相互変換を行います。RPC システム内 (例えば、rpcbind とクライアントの間) では、汎用アドレスが使用されます。各トランスポートには、名前からアドレスへの変換ルーチンの入った実行時リンクライブラリがあります。表 2–7 に、主な変換ルーチンを示します。

上の各ルーチンについての詳細は、netdir(3NSL) のマニュアルページを参照してください。どのルーチンの場合も、netconfig 構造体が名前からアドレスへの変換のコンテキストを提供していることに注意してください。

表 2–7 名前からアドレスへの変換ルーチン

netdir_getbyname ()

ホストとサービスのペア(たとえば、server1rpcbind) と netconfig 構造体から、netbuf アドレスのセットに変換する。netbuf は TLI 構造体で、実行時にトランスポート固有のアドレスが入る

 

netbuf()アドレスと netconfig 構造体から、ホストとサービスのペアに変換する

uaddr2taddr()

汎用アドレスと netconfig() 構造体から、netbuf アドレスに変換する

taddr2uaddr ()

netbuf アドレスと netconfig 構造体から、汎用アドレスに変換する

アドレスルックアップサービス

トランスポートサービスにはアドレスルックアップサービスは含まれていません。トランスポートサービスはネットワーク上のメッセージ転送だけを行います。クライアントプログラムは、使用するサーバープログラムのアドレスを知る必要があります。旧バージョンの SunOS では、portmap デーモンがそのサービスを実行していました。現バージョンでは、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 を頻繁に呼び出さなくて済むように、最後に呼び出したリモートプログラムのネットワークアドレスを保存されています。

rpcbindRPCBPROC_CALLIT 手続きを使用すると、クライアントはサーバーのアドレスがわからなくてもリモートプロシージャを呼び出すことができます。クライアントは目的の手続きのプログラム番号、バージョン番号、手続き番号、引数を RPC 呼び出しメッセージで引き渡します。rpcbind は、アドレスマップから目的の手続きのアドレスを探し出し、RPC 呼び出しメッセージにクライアントから受け取った引数を入れて、その手続きに送信します。

目的の手続きから結果が返されると、RPCBPROC_CALLIT はクライアントプログラムにその結果を引き渡します。そのとき、目的の手続きの汎用アドレスも同時に渡されますので、次からはクライアントが直接その手続きを呼び出すことができます。

RPC ライブラリは rpcbind の全手続きのインタフェースを提供します。RPC ライブラリの手続きには、クライアントとサーバーのプログラムのために rpcbind を自動的に呼び出すものもあります。詳細については、RPC 言語の仕様 を参照してください。

RPC 情報の取り出し

rpcinfo は、rpcbind で登録した RPC の最新情報を取り出すユーティリティです。rpcbind または portmap ユーティリティと共に rpcinfo を使用して、あるホストに登録されたすべての RPC サービスの汎用アドレスとトランスポートを知ることができます。rpcinfo では、指定したホスト上で指定したプログラムの特定バージョンを呼び出して、応答が返ったかどうかを調べることができます。また、rpcinfo は、登録を削除することもできます。詳細については、rpcinfo(1M) のマニュアルページを参照してください。