この章では、このマニュアルの rpcgen と RPC の章で使用したサンプルプログラムを示します。特に但し書き (擬似プログラムであるというような) がない限り、このまま書かれているとおりにコンパイルして実行できます。これらのサンプルプログラムはマニュアルの説明を補うために示すものです。Sun は実行結果に対してどのような責任も負いません。
/* * dir.x: 遠隔ディレクトリリストの * プロトコル * * このソースモジュールは rpcgen が生成したソースモジュールです。 * これを使用して rpcgen ツールの機能を説明します。 * * このプログラムは、rpcgen の -h -T のスイッチを使用して * ヘッダーファイル (.h) と付随するデータ構造体も同時に生成して * コンパイルします。 * */ const MAXNAMELEN = 255; /* ディレクトリエントリの最大長 */ typedef string nametype<MAXNAMELEN>; /* ディレクトリエントリ */ typedef struct namenode *namelist; /* リスト内のリンク */ /* * ディレクトリリスト内のノード struct namenode */ struct namenode { nametype name; /* ディレクトリエントリ名 */ namelist next; /* 次のエントリ */ }; /* * READDIR 操作の結果: * 完全に移植可能なアプリケーションにするには、ここで行なっているように * UNIX の errno を使用せずに、取り決めに従ったエラーコードリストを * 使用します。この例では、遠隔呼び出しが成功したか失敗したかを * 識別するのに共用体を使用しています。 */ union readdir_res switch (int errno) { case 0: namelist list; /* エラーなし: ディレクトリリストを返す */ default: void; /* エラー発生: 戻り値なし */ }; /* * ディレクトリリストプログラムの定義 */ program DIRPROG { version DIRVERS { readdir_res READDIR(nametype) = 1; } = 1; } = 0x20000076; |
/* * dir_proc.c: 遠隔手続き readdir */ #include <rpc/rpc.h> /* 必ず必要 */ #include <dirent.h> #include "dir.h" /* rpcgen が生成 */ extern int errno; extern char *malloc(); extern char *strdup(); /* 使用する引数 */ readdir_res * readdir_1(dirname,req) nametype *dirname; struct svc_req *req; { DIR *dirp; struct dirent *d; namelist nl; namelist *nlp; static readdir_res res; /* 必ず static で宣言 */ /* * ディレクトリのオープン */ dirp = opendir(*dirname); if (dirp == (DIR *)NULL) { res.errno = errno; return (&res); } /* * 以前の結果を解放 */ xdr_free(xdr_readdir_res, &res); /* * ディレクトリエントリの収集。ここで割り当てられたメモリーは、 * 次に readdir_1 が呼び出されたときに xdr_free によって解放されます。 */ nlp = &res.readdir_res_u.list; while (d = readdir(dirp)) { nl = *nlp = (namenode *) malloc(sizeof(namenode)); if (nl == (namenode *) NULL) { res.errno = EAGAIN; closedir(dirp); return(&res); } nl->name = strdup(d->d_name); nlp = &nl->next; } *nlp = (namelist)NULL; /* 結果を返す */ res.errno = 0; closedir(dirp); return (&res); } |
/* * rls.c: 遠隔ディレクトリリスト (クライアント側) */ #include <stdio.h> #include <rpc/rpc.h> /* 必ず必要 */ #include "dir.h" /* rpcgen が生成 */ extern int errno; main(argc, argv) int argc; char *argv[]; { CLIENT *cl; char *server; char *dir; readdir_res *result; namelist nl; if (argc != 3) { fprintf(stderr, "usage: %s host directory¥n", argv[0]); exit(1); } server = argv[1]; dir = argv[2]; /* * コマンド行で指定したサーバー上の MESSAGEPROG の呼び出しに使用する * クライアント「ハンドル」を作成します。 */ cl = clnt_create(server, DIRPROG, DIRVERS, "visible"); if (cl == (CLIENT *)NULL) { clnt_pcreateerror(server); exit(1); } result = readdir_1(&dir, cl); if (result == (readdir_res *)NULL) { clnt_perror(cl, server); exit(1); } /* 遠隔手続きの呼び出しに成功 */ if (result->errno != 0) { /* * 遠隔システムでエラーが発生。エラーメッセージを表示して終了。 */ } if (result->errno < sys_nerr) fprintf (stderr, "%s : %s¥n", dir, sys_enlist[result->errno]); errno = result->errno; perror(dir); exit(1); } /* ディレクトリリストの取り出しに成功。ディレクトリリストを表示 */ for(nl = result->readdir_res_u.list; nl != NULL; nl = nl- >next) { printf("%s¥n", nl->name); } exit(0); |
/* * time.x: 遠隔時刻プロトコル */ program TIMEPROG { version TIMEVERS { unsigned int TIMEGET(void) = 1; } = 1; } = 0x20000044; #ifdef RPC_SVC %int * %timeget_1() %{ % static int thetime; % % thetime = time(0); % return (&thetime); %} #endif |
/* 新たな rpcgen 機能を説明するために、このプログラムには * 2 つの数値を加える手続きが入っています。ここでは add() が 2 つの引数を取ること * に注意してください。 */ program ADDPROG { /* プログラム番号 */ version ADDVER { /* バージョン番号 */ int add ( int, int ) /* 手続き */ = 1; } = 1; } = 199; |
このツールの使用方法については、spray(1M) のマニュアルページの注を参照してください。
/* * copyright (c) 1987,1991 by Sun Microsystems,Ins. */ /* spray.x から */ #ifdef RPC_HDR #pragma ident "@(#)spray.h 1.2 91/09/17 SMI" #endif /* * サーバーにパケットをスプレイします。 * ネットワークインタフェースのもろさのテストに使用します。 */ const SPRAYMAX = 8845; /* スプレイ可能な最大量 */ /* * 1970 年 1 月 1 日 0:00 からの GMT */ struct spraytimeval { unsigned int sec; unsigned int usec; }; /* * スプレイ統計情報 */ struct spraycumul { unsigned int counter; spraytimeval clock; }; /* * スプレイデータ */ typedef opaque sprayarr<SPRAYMAX>; program SPRAYPROG { version SPRAYVERS { /* * データを捨てて、カウンタをインクリメントします。この呼び出しは * 終了しないため、クライアントは必ずタイムアウトになります。 */ void SPRAYPROC_SPRAY(sprayarr) = 1; /* * カウンタ値と、最後にクリアしたときからの経過時間を取り出します。 */ spraycumul SPRAYPROC_GET(void) = 2; /* * カウンタをクリアし、経過時間をリセットします。 */ void SPRAYPROC_CLEAR(void) = 3; } = 1; } = 100012; |
/* printmsg.c: コンソールにメッセージを表示 */ #include <stdio.h> main(argc, argv) int argc; char *argv[]; { char *message; if (argc != 2) { fprintf(stderr, "usage: %s <message>¥n", argv[0]); exit(1); } message = argv[1]; if( !printmessage(message) ) { fprintf(stderr, "%s: couldn't print your message¥n", argv[0]); exit(1); } printf("Message Delivered!¥n"); exit(0); } /* コンソールにメッセージを表示します。 */ /* * メッセージが実際に表示されたかどうかを示すブール値を返します。 */ printmessage(msg) char *msg; { FILE *f; if = fopen("/dev/console","w"); if (f == (FILE *)NULL) return (0); fprintf(f,"%sen", msg); fclose(f); return (1); } |
/* * rprintmsg.c: printmsg.c の遠隔バージョン */ #include <stdio.h> #include <rpc/rpc.h> /* 必ず必要 */ #include "msg.h" /* msg.h は rpcgen が生成 */ main(argc, argv) int argc; char *argv[]; { CLIENT *cl; int *result; char *server; char *message; extern int sys_nerr; extern char *sys_errlist[]; if (argc != 3) { fprintf(stderr,"usage: %s host messagen", argv[0]); exit(1); } /* * コマンド行で指定した引数の値を保存します。 */ server = argv[1]; message = argv[2]; /* * コマンド行で指定したサーバー上の MESSAGEPROG の呼び出しに使用する * クライアント「ハンドル」を作成します。 */ cl = clnt_create(server, MESSAGEPROG, PRINTMESSAGEVERS, "visible"); if (cl == (CLIENT *)NULL) { /* * サーバーとの接続の確立に失敗。 * エラーメッセージを表示して終了します。 */ clnt_pcreateerror(server); exit(1); } /* サーバー上の遠隔手続き printmessage を呼び出します。 */ result = printmessage_1(&message, cl); if (result == (int *)NULL) { /* * サーバーの呼び出しでエラーが発生。 * エラーメッセージを表示して終了します。 */ clnt_perror(cl, server); exit(1); } /* 遠隔手続きの呼び出しに成功。 */ if (*result == 0) { /* * サーバーはメッセージの表示に失敗。 * エラーメッセージを表示して終了します。 */ fprintf(stderr,"%s" } /* サーバーのコンソールにメッセージが出力されました。 */ printf("Message delivered to %s!¥n", server); exit(0); } |
/* msg.x: 遠隔メッセージ印刷プロトコル */ program MESSAGEPROG { version MESSAGEVERS { int PRINTMESSAGE(string) = 1; } = 1; } = 0x20000001; |
/* * msg_proc.c: 遠隔手続き printmessage */ #include <stdio.h> #include <rpc/rpc.h> /* 必ず必要 */ #include "msg.h" /* msg.h は rpcgen が生成 */ /* * printmessage の遠隔バージョン */ /* 使用する引数 */ int printmessage_1(msg, req) char **msg; struct svc_req *req; { static int result; /* 必ず static で宣言 */ FILE *f; f = fopen("/dev/console", "w"); if (f == (FILE *)NULL) { result = 0; return (&result); } fprintf(f, "%sen", *msg); fclose(f); result = 1; return (&result); } |
#include <stdio.h> #include <rpc/rpc.h> #include "windows.h" main(argc, argv) int argc; char **argv; { struct timeval total_timeout; register CLIENT *client; enum clnt_stat clnt_stat; char buf[1000], *s = buf; if ((client = clnt_create(argv[1], WINDOWPROG, WINDOWVERS, "CIRCUIT_V")) == (CLIENT *) NULL) { clnt_pcreateerror("clnt_create"); exit(1); } timerclear(&total_timeout); while (scanf("%s", s) != EOF) { clnt_call(client, RENDERSTRING_BATCHED, xdr_wrapstring, &s,xdr_void, (caddr_t) NULL, total_timeout); } /* ここでパイプラインをフラッシュ */ total_timeout.tv_sec = 20; clnt_stat = clnt_call(client, NULLPROC, xdr_void, (caddr_t) NULL, xdr_void, (caddr_t) NULL, total_timeout); if (clnt_stat != RPC_SUCCESS) { clnt_perror(client, "rpc"); exit(1); } clnt_destroy(client); exit(0); } |
#include <stdio.h> #include <rpc/rpc.h> #include "windows.h" void windowdispatch(); main() { int num; num = svc_create(windowdispatch, WINDOWPROG, WINDOWVERS, "CIRCUIT_V"); if (num == 0) { fprintf(stderr, "can't create an RPC server¥n"); exit(1); } svc_run(); /* 戻らない */ fprintf(stderr, "should never reach this point¥n"); } void windowdispatch(rqstp, transp) struct svc_req *rqstp; SVCXPRT *transp; { char *s = NULL; switch (rqstp->rq_proc) { case NULLPROC: if (!svc_sendreply(transp, xdr_void, 0)) fprintf(stderr, "can't reply to RPC call¥n"); return; case RENDERSTRING: if (!svc_getargs(transp, xdr_wrapstring, &s)) { fprintf(stderr, "can't decode arguments¥n"); /* 呼び出し側にエラーを通知 */ svcerr_decode(transp); break; } /* 文字列 s を処理するコード */ if (!svc_sendreply(transp, xdr_void, (caddr_t) NULL)) fprintf(stderr, "can't reply to RPC call¥n"); break; case RENDERSTRING_BATCHED: if (!svc_getargs(transp, xdr_wrapstring, &s)) { fprintf(stderr, "can't decode arguments¥n"); /* プロトコルエラーのため何も返さない */ break; } /* 文字列 s を処理するコード。ただし応答はしない。 */ break; default: svcerr_noproc(transp); return; } /* 引数の復号化で割り当てた文字列を解放 */ svc_freeargs(transp, xdr_wrapstring, &s); } |
次のプログラムは参考のためだけに示します。バッチを使用するクライアントプログラムの例を、バッチを使用しないように書き直したものです。
#include <stdio.h> #include <rpc/rpc.h> #include "windows.h" main(argc, argv) int argc; char **argv; { struct timeval total_timeout; register CLIENT *client; enum clnt_stat clnt_stat; char buf[1000], *s = buf; if ((client = clnt_create(argv[1], WINDOWPROG, WINDOWVERS, "CIRCUIT_V")) == (CLIENT *) NULL) { clnt_pcreateerror("clnt_create"); exit(1); } total_timeout.tv_sec = 20; total_timeout.tv_usec = 0; while (scanf("%s", s) != EOF) { if(clnt_call(client, RENDERSTRING, xdr_wrapstring, &s, xdr_void, (caddr_t) NULL, total_timeout) != RPC_SUCCESS) { clnt_perror(client, "rpc"); exit(1); } } clnt_destroy(client); exit(0); } |