分散システム
電子・情報工学系
新城 靖
<yas@is.tsukuba.ac.jp>
このページは、次の URL にあります。
http://www.hlla.is.tsukuba.ac.jp/~yas/coins/dsys-1998/1999-01-26
/sunrpc-types.html
あるいは、次のページから手繰っていくこともできます。
http://www.hlla.is.tsukuba.ac.jp/~yas/coins/
http://www.hlla.is.tsukuba.ac.jp/~yas/index-j.html
RPCのインタフェースの定義では、定数を記述することができます。
const LSIZE = 80 ;これは、
rpcgen により、C言語のプリプロセッサのマクロ
#defineに置き換えられます。
RPCのインタフェースの定義では、配列を定義することができる。配列には、
固定長と可変長の2種類あり、固定長は、C言語と同じ。可変長は、次のよう
に[]の代わりに<>とする。
int varray<>;
<> の中には、最大長を書くこともできる。これは、
rpcgen により、次のような構造体に置き換えられる。
struct {
u_int varray_len;
int *varray_val;
} varray;
typedef struct varray varray ;
C言語でプログラムを作成する時には、この varray_len に要素数を、
varray_val に、配列の先頭のポインタをセットする。
int a1[10] ; varray v1 ; v1.varray_len = 10 ; v1.varray_val = &a1[0] ;文字列を送るには、特殊な
string 型を使う。
string s<> ;これは、C言語では、
char * になるが、文字列のつもりで次のよう
に書いても、文字列は送られない。
char *s ;これも、
rpcgen により、やはり char * にコンパイルされる
が、この場合、ポインタの先の1文字しか送られない。C言語の文字列を送り
たい時には、必ず string を使うこと。
SunRPC ではポインタ型も送ること ができるが、ポインタの先の1要素しか送られない。 複数要素を送りいた時には、配列を使う。
C言語の main の引数と同様の構造を送りたい時には、次のようにする。
typedef string argstr_t<>; typedef argstr_t argvt<>;大量のデータをそのまま送るには、
opaque
型
(
不定形型
)
を使う。これには固定長と可変長がある。
opaque fileblock[512] ; opaque filedata<> ;
opaque の代わりにchar の配列にすると、文字と見なして1
文字1文字変換が行なわれることになり、非常に遅くなる。場合によっては文
字コードの変換が行なわれる。opaque では、そのような変換は一切
行なわれず、そのままの形で送られる。
RPCのインタフェースの定義では、共用体(可変長の構造体)が書ける。
union int_result_t
switch( int status )
{
case OK:
int data ;
default:
void;
};
これは、次のようにコンパイルされる。
struct int_result_t {
int status;
union {
int data;
} int_result_t_u;
};
status という値がOK の時だけdata が有効になる。
すなわち、その時だけ実際にネットワークにたいしてdata の部分が
送られる。
RPCのインタフェースの定義では、
bool_t という型が使える。値は、
TRUE か FALSE 。
date.x:
----------------------------------------------------------------------
1:
2: /*
3: date.x -- 日付時刻サービス
4: このファイルは、次の場所にあります。
5: ~yas/dsys/rpc-date/date.x
6: cp コマンドでコピーできます。
7: $Header: /home/lab2/OS/yas/dsys/rpc-date/RCS/date.x,v 1.4 1999/01/25 18:00:46 yas Exp $
8: Start: 1999/01/26 02:16:33
9: */
10:
11: struct ds_timeval
12: {
13: long clock ;
14: };
15:
16: struct ds_datestr
17: {
18: string str<> ;
19: };
20:
21: program DATE_PROG {
22: version DATE_VERSION {
23: ds_timeval GETTIMEVAL(void) = 11 ;
24: ds_datestr GETDATESTR(void) = 12 ;
25: } = 1 ;
26: } = 0x20001002 ;
----------------------------------------------------------------------
string1つでも構造体にした方がわかりやすい。
date_server.c:
----------------------------------------------------------------------
1:
2: /*
3: date_server.x -- 日付時刻サービス/サーバ側の手続き
4: このファイルは、次の場所にあります。
5: ~yas/dsys/rpc-date/date_server.c
6: cp コマンドでコピーできます。
7: $Header: /home/lab2/OS/yas/dsys/rpc-date/RCS/date_server.c,v 1.3 1999/01/25 17:59:03 yas Exp $
8: Start: 1999/01/26 02:16:33
9: */
10:
11: #include <rpc/rpc.h>
12: #include "date.h"
13:
14: ds_timeval *
15: gettimeval_1()
16: {
17: static ds_timeval res ;
18: res.clock = time( 0 ); /* BSD: gettimeofday() */
19: return( &res );
20: }
21:
22: ds_datestr *
23: getdatestr_1()
24: {
25: static ds_datestr res ;
26: char buf[100] ;
27: time_t now ;
28: struct tm *tm_now ;
29: int len ;
30: if( res.str )
31: {
32: free( res.str );
33: res.str = 0 ;
34: }
35: now = time( 0 );
36: tm_now = localtime( &now );
37: len = strftime( buf, 100, "%a %b %d %H:%M:%S %Z %Y", tm_now );
38: if( len == 0 )
39: return( 0 );
40: res.str = (char *)malloc( len+1 );
41: if( res.str == 0 )
42: return( 0 );
43: strncpy( res.str, buf, len );
44: res.str[len] = 0 ;
45: return( &res );
46: }
----------------------------------------------------------------------
malloc() してリターンして、次に回って来た時に free() する。
date_client.c
----------------------------------------------------------------------
1:
2: /*
3: date_server.x -- 日付時刻サービス/クライアント側の手続き
4: このファイルは、次の場所にあります。
5: ~yas/dsys/rpc-date/date_server.c
6: cp コマンドでコピーできます。
7: $Header: /home/lab2/OS/yas/dsys/rpc-date/RCS/date_client.c,v 1.3 1999/01/25 17:59:03 yas Exp $
8: Start: 1999/01/26 02:16:33
9: */
10:
11: #include <stdio.h>
12: #include <rpc/rpc.h>
13: #include "date.h"
14:
15: main( int argc, char *argv[] )
16: {
17: CLIENT *cl;
18: char dummy ;
19: ds_datestr *result ;
20: char *server_name;
21:
22: if( argc != 2 ) {
23: fprintf(stderr, "usage: %s server\n", argv[0]);
24: exit(1);
25: }
26: server_name = argv[1];
27: cl = clnt_create( server_name, DATE_PROG, DATE_VERSION, "tcp" );
28: if( cl == NULL ) {
29: clnt_pcreateerror( server_name );
30: exit( 1 );
31: }
32: result = getdatestr_1( &dummy, cl );
33: if( result == NULL ) {
34: clnt_perror( cl, server_name );
35: exit( 1 );
36: }
37: printf("getdatestr() returns %s \n",
38: result->str );
39: xdr_free( xdr_ds_datestr, (char *)result );
40: }
----------------------------------------------------------------------
% makerpcgen date.x cc -g -c date_client.c -o date_client.o cc -g -c date_clnt.c -o date_clnt.o cc -g -c date_xdr.c -o date_xdr.o cc -o date_client date_client.o date_clnt.o date_xdr.o cc -g -c date_server.c -o date_server.o cc -g -c date_svc.c -o date_svc.o cc -o date_server date_server.o date_svc.o date_xdr.o %
![]()
サーバ側は止まらないので、止めたい時には、% ./date_server![]()
^C を押す。
ホスト名には、localhost が便利。
% ./date_client localhostgetdatestr() returns Tue Jan 26 03:05:24 JST 1999 %
![]()
Sunの技術で、構造体をファイルに保存することができる。
構造体を整列化し、他のプロセスに通信メッセージとして送る代わりにファイ ルに保存する。
SunRPCでは、xdrstdio_create() という関数が用意されています。 ストリーム入出力(FILE *) に対して構造体を読み書きすることができるようになる。
RPCと同様に、構造体にポインタが含まれていた場合、再帰的にファイルに保 存される。異なる機種で読み出すことができる。