遠隔手続き呼び出しのときにデータは XDR 標準形式で伝送されますので、XDR は米国サンソフトの RPC パッケージの重要な基本概念となっています。複数の異なるタイプのマシンからアクセスされる (読み書きされる) データの転送には、XDR ライブラリルーチンを使用する必要があります。
XDR は異なる言語、異なるオペレーティングシステム、異なるマシンアーキテクチャの間で機能します。ほとんどのユーザ (特に RPC ユーザ) は、「整数フィルタ」、「浮動小数点フィルタ」、「列挙型フィルタ」の節を読むだけで十分でしょう。RPC と XDR を別のマシン上に
RPC 呼び出しを行わない場合でも、rpcgen を使用して XDR ルーチンを書くことができます。
XDR ルーチンを使用する C プログラムはファイル <rpc/xdr.h> をインクルードしなければなりません。<rpc/xdr.h> には、XDR システムとの必要なインタフェースがすべて入っています。XDR ルーチンはすべてライブラリlibnsl.a に入っていますので、コンパイルは次のコマンドで実行します。
example% cc program.c
移植性を保つためには、各環境でさまざまな基準を守ってプログラミングしなければなりません。プログラミング方法の微妙な違いを見つけるのも必ずしも簡単とはいえませんが、それらが広範囲に渡って関連し合っています。以下に示すサンプルプログラム 例 A-1 と 例 A-2(テキスト行の読み込みと書き出しのプログラム) で考えてみましょう。
#include <stdio.h> main() /* writer.c */ { long 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 */ { long 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); }
この 2 つのプログラムは移植可能に見えます。なぜならば、(a) lint チェックをパスし、(b) 2 つの異なるハードウェアアーキテクチャ、SPARC と VAX 上で実行しても同じように動作するからです。
writer プログラムの出力を reader プログラムにパイプした場合も、SPARC と VAX の両方で同じ結果が得られます。
sun% writer | reader 0 1 2 3 4 5 6 7 sun% vax% writer | reader 0 1 2 3 4 5 6 7 vax%
ローカルエリアネットワークと 4.2BSD の出現に伴って、「ネットワークパイプ」の概念が導入されました。すなわち、あるマシン上のプロセスで生成したデータを、別のマシン上のプロセスが使用するという概念です。writer と reader のプログラムでも、ネットワークパイプを使用できます。最初にSPARC 上でデータを生成し、そのデータを VAX 上で使用したときの実行結果を次に示します。
sun% writer | rsh vax reader 0 16777216 33554432 50331648 67108864 83886080 100663296 117440512 sun%
writer を VAX で実行し、reader を SPARCで実行した場合も同じ結果になります。この原因は、VAX と SPARC の long 型整数は、ワードサイズは同じでもバイト順序が異なるためです。16777216 は です。4 バイトを逆順にすると、24 番目のビットに 1 が置かれることに注意してください。
複数の異なるタイプのマシンでデータを共有するときは、データの移植性についての注意が必要です。データを移植可能にするには、プログラム内の read() や write() の呼び出しを XDR ライブラリルーチン xdr_long() に置き換えます。xdr_long()はフィルタルーチン 例 A-3 に示します。
#include <stdio.h> #include <rpc/rpc.h> /* XDR は RPC のサブライブラリ */ main() /* writer.c */ { XDR xdrs; long i; xdrstdio_create(&xdrs, stdout, XDR_ENCODE); for (i = 0; i < 8; i++) { if (!xdr_long(&xdrs, &i)) { fprintf(stderr, "failed!¥n"); exit(1); } } exit(0); }
例 A-4 のサンプルプログラムは、readerプログラムを修正したものです。
#include <stdio.h> #include <rpc/rpc.h> /* xdr は rpc のサブライブラリ */ main() /* reader.c */ { XDR xdrs; long i, j; xdrstdio_create(&xdrs, stdin, XDR_DECODE); for (j = 0; j < 8; j++) { if (!xdr_long(&xdrs, &i)) { fprintf(stderr, "failed!¥n"); exit(1); } printf("%ld ", i); } printf("¥n"); exit(0); }
変更したプログラムを SPARC 上で実行した結果、VAX 上で実行した結果、および SPARC から VAX にパイプした結果を次に示します。
sun% writer | reader 0 1 2 3 4 5 6 7 sun% vax% writer | reader 0 1 2 3 4 5 6 7 vax% sun% writer | rsh vax reader 0 1 2 3 4 5 6 7 sun%
整数データの移植問題は、データの移植問題のごく簡単な一例にすぎません。どのデータ構造体にも移植性の問題があり、特にデータ境界とポインタが大きな問題になります。ワード境界の違いにより、マシンごとに構造体のサイズが異なる可能性があります。ポインタは使用するには便利ですが、ポインタが定義されたマシンの外部では何の意味も持ちません。