XDR は Sun のリモートプロシージャコール (RPC) パッケージの中枢です。 RPC 用データはこの標準規格を使って転送されます。複数の異なるタイプのマシンからアクセスされる (読み書きされる) データの転送には、XDR ライブラリルーチンを使用する必要があります。
XDR は異なる言語、異なるオペレーティングシステム、異なるマシンアーキテクチャの間で機能します。ほとんどのユーザー (特に RPC ユーザー) は、「整数フィルタ」、「浮動小数点フィルタ」、「列挙型フィルタ」の節を読むだけで十分でしょう。RPC と XDR を別のマシン上に実装するプログラマは、このテクニカルノートやプロトコル仕様を読んでください。
RPC 呼び出しを行わない場合でも、rpcgen を使用して XDR ルーチンを書くことができます。
XDR ルーチンを使用する C プログラムはファイル <rpc/xdr.h> をインクルードする必要があります。<rpc/xdr.h> には、必要な XDR システムとのインタフェースがすべて入っています。ライブラリ libnsl.a にはすべての XDR ルーチンが含まれているため、コンパイルは次のコマンドで実行します。
example% cc program.c |
移植性を保つためには、各環境でさまざまな基準を守ってプログラミングしなければなりません。小さなプログラム上の変更の影響は外見上明らかにならない場合もありますが、しばしば、大きな影響を持ちます。次の 2 つのサンプルプログラム (テキスト行の読み込みと書き出しのプログラム) で考えてみましょう。
#include <stdio.h> main() /* writer.c */ { int i; for (i = 0; i < 8; i++) { if (fwrite((char *) &i, sizeof(i), 1, stdout) != 1) { fprintf(stderr, "failed!\n"); exit(1); } } exit(0); }
#include <stdio.h> main() /* reader.c */ { int i, j; for (j = 0; j < 8; j++) { if (fread((char *) &i, sizeof(i), 1, stdin) != 1) { fprintf(stderr, "failed!\n"); exit(1); } printf("%ld ", i); } printf("\n"); exit(0); }
lint チェックにパスしている
どのハードウェアアーキテクチャ上でローカルに実行した場合も同じ動作を示す
writer プログラムの出力を reader プログラムにパイプした場合も、SPARC と Intel マシンの両方で同じ結果が得られます。
sun% writer | reader 0 1 2 3 4 5 6 7 sun% intel% writer | reader 0 1 2 3 4 5 6 7 intel%
ローカルエリアネットワークと 4.2BSD の出現に伴って、「ネットワークパイプ」の概念が導入されました。すなわち、あるマシン上のプロセスで生成したデータを、別のマシン上のプロセスが使用するという概念です。writer とreader を使用してネットワークパイプを構築できます。次は SPARC システム上で writer がデータを生成し、そのデータを Intel アーキテクチャ上で reader が使用した場合です。
sun% writer | rsh intel reader 0 16777216 33554432 50331648 67108864 83886080 100663296 117440512 sun%
Intel 上で writer 、SPARC 上で reader を実行した場合も同一の結果となります。 この原因は、Intel と SPARC の int 型整数は、ワードサイズは同じでもデータのバイト順序が異なるためです。
16777216 は 224 です。4 バイトを逆順にすると、24 番目のビットに 1 が置かれます。
複数の異なるタイプのマシンでデータを共有するときは、データの移植性についての注意が必要です。read() と write() 呼び出しを XDR ライブラリルーチンの呼び出しで xdr_int() に置き換えることにより、データを移植可能にすることができます。xdr_int() は、int 型の整数の外部用の標準的な表現を扱うことができるフィルタです。次のコーディング例では、writer の改訂バージョンを示します。
#include <stdio.h> #include <rpc/rpc.h> /* XDR は RPC のサブライブラリ */ main() /* writer.c */ { XDR xdrs; int i; xdrstdio_create(&xdrs, stdout, XDR_ENCODE); for (i = 0; i < 8; i++) { if (!xdr_int(&xdrs, &i)) { fprintf(stderr, "failed!\n"); exit(1); } } exit(0); }
次のコーディング例は reader の改訂バージョンです。
#include <stdio.h> #include <rpc/rpc.h> /* xdr は rpc のサブライブラリ */ main() /* reader.c */ { XDR xdrs; int i, j; xdrstdio_create(&xdrs, stdin, XDR_DECODE); for (j = 0; j < 8; j++) { if (!xdr_int(&xdrs, &i)) { fprintf(stderr, "failed!\n"); exit(1); } printf("%ld ", i); } printf("\n"); exit(0); }
変更したプログラムを SPARC システム上で実行した結果、Intel 上で実行した結果、および SPARC から Intel にパイプした結果を次に示します。
sun% writer | reader 0 1 2 3 4 5 6 7 sun% intel% writer | reader 0 1 2 3 4 5 6 7 intel% sun% writer | rsh intel reader 0 1 2 3 4 5 6 7 sun%
どのデータ構造体にも移植性の問題が生じる場合があり、特にデータ境界とポインタが大きな問題になります。ワード境界の違いにより、マシンごとに構造体のサイズが異なります。ポインタは使用するには便利ですが、ポインタが定義されたマシンの外部では何の意味も持ちません。