情報学類 分散システム 2008年12月25日 筑波大学システム情報工学研究科 コンピュータサイエンス専攻, 電子・情報工学系 新城 靖 <yas@is.tsukuba.ac.jp>
このページは、次の URL にあります。
http://www.coins.tsukuba.ac.jp/~yas/coins/dsys-2008/2008-12-25
あるいは、次のページから手繰っていくこともできます。
http://www.coins.tsukuba.ac.jp/~yas/
http://www.cs.tsukuba.ac.jp/~yas/
第2章 基盤技術 (新城) 2.6節 遠隔手続き呼出し
例:手続き put()。ハッシュ表にデータを格納する手続きで、引数にキーとな
る文字列と値となる整数を取る。
図? スタブによるRPCの実現
typedef string key_t<256>; struct keyvalue_t { key_t key; int value ; }; typedef key_t keyarray_t<>; program HASHTABLE_PROG { version HASHTABLE_VERSION { int PUT(keyvalue_t) = 11 ; int GETVALUE(string) = 12 ; keyarray_t GETKEYS(void) = 13 ; } = 1 ; } = 0x20051001 ;インタフェース定義をスタブ生成器に与えると、クライアント側スタブ、サー バ側スタブが自動的に生成される。
インタフェース記述の内容
intなど基本型 | 構造体 | オブジェクト | 配列 | |
C言語 | 値 | 値 | - | 自動ポインタ値化* |
Java | 値 | - | 参照 | 参照 |
言語が持つ意味を、RPCでは再現できないことがある。
1: #include <stdio.h> 2: 3: int square( int a ) { 4: a = a * a ; 5: return( a ); 6: } 7: 8: main() { 9: int x, y, result; 10: x = 10; 11: y = 20; 12: result = square( x ); 13: printf("x==%d, result==%d\n", x, result); 14: result = square( y++ ); 15: printf("y==%d, result==%d\n", y, result); 16: }実行結果
% make square-value
cc square-value.c -o square-value
% ./square-value
x==10, result==100
y==21, result==400
%
1: #include <stdio.h> 2: 3: int square( int &a ) { 4: a = a * a ; 5: return( a ); 6: } 7: 8: main() { 9: int x, y, result; 10: x = 10; 11: y = 20; 12: result = square( x ); 13: printf("x==%d, result==%d\n", x, result); 14: // result = square( y++ ); 15: // printf("y==%d, result==%d\n", y, result); 16: }実行結果。引数で渡した変数 x の値が書き換えられている。
% make square-ref
g++ square-ref.cc -o square-ref
% ./square-ref
x==100, result==100
%
C++の参照型では、引数には、変数しかかけない。y++ のような式では、コンパ
イル時にエラーになる。
% cat -n square-ref.cc
1 #include <stdio.h>
2
3 int square( int &a ) {
4 a = a * a ;
5 return( a );
6 }
7
8 main() {
9 int x, y, result;
10 x = 10;
11 y = 20;
12 result = square( x );
13 printf("x==%d, result==%d\n", x, result);
14 result = square( y++ );
15 printf("y==%d, result==%d\n", y, result);
16 }
% make square-ref
g++ square-ref.cc -o square-ref
square-ref.cc: In function 'int main()':
square-ref.cc:14: error: invalid initialization of non-const reference of type 'int&' from a temporary of type 'int'
square-ref.cc:3: error: in passing argument 1 of 'int square(int&)'
make: *** [square-ref] Error 1
C++の参照型は、プログラムが読みにくくなるので使ってはいけない。
main() { int x ; x = 10 ; f( x ); printf("%d\n",x); }C言語のレベルでは、f(x) と呼んでも、決して x の値は、変化しない。C++の 参照型を使えば、f() の型宣言を見ないと、変化するか変化しないかわからな い。「型宣言を見る」という手間の分だけ、プログラムが読みにくくなる。 全部の関数について、見ていたら疲れる。
1: #include <stdio.h> 2: 3: int square( int *a ) { 4: *a = *a * *a ; 5: return( *a ); 6: } 7: 8: main() { 9: int x, y, result, *xp, *yp; 10: x = 10; xp = &x; 11: y = 20; yp = &y; 12: result = square( xp ); 13: printf("x==%d, result==%d, &x==0x%x, xp==0x%x\n", 14: x, result, &x, xp); 15: result = square( yp++ ); 16: printf("y==%d, result==%d, &y==0x%x, yp==0x%x\n", 17: y, result, &y, yp); 18: }
% make square-pointer
cc square-pointer.c -o square-pointer
% ./square-pointer
x==100, result==100, &x==0xbffff534, xp==0xbffff534
y==400, result==400, &y==0xbffff538, yp==0xbffff53c
%
C++の参照型は、プログラムが読みにくくなるので使ってはいけないが、
C言語のポインタ渡しは、使ってもよい。
main() { int x ; x = 10 ; f( &x ); printf("%d\n",x); }C言語のレベルでは、f(&x) と&を付けた段階で、 f() の内容を知らなくてもx の値が変化することが推察される。値が変化する 可能性について、ポインタを渡している関数だけ注意すればよい。
main() { int a[10] ; f( a ); f( &a ); f( &a[0] ); }配列を自動的にポインタに変換する歴史的な理由
1: #include <stdio.h> 2: 3: #define square( a ) ((a)*(a)) 4: 5: main() { 6: int x, y, result; 7: x = 10; 8: y = 20; 9: result = square( x ); 10: printf("x==%d, result==%d\n", x, result); 11: result = square( y++ ); 12: printf("y==%d, result==%d\n", y, result); 13: }実行結果。y++ と 1 度書いただけなのに、2 増えている。
% make square-macro
cc square-macro.c -o square-macro
% ./square-macro
x==10, result==100
y==22, result==400
%
マクロ展開だけして止めてみるとわかる。
% cc -E square-macro.c > square-macro.i
% wc square-macro.i
421 1135 9164 square-macro.i
% tail -13 square-macro.i
# 2 "square-macro.c" 2
main() {
int x, y, result;
x = 10;
y = 20;
result = ((x)*(x));
printf("x==%d, result==%d\n", x, result);
result = ((y++)*(y++));
printf("y==%d, result==%d\n", y, result);
}
%
1: #include <stdio.h> 2: 3: int square_a; 4: int square() { 5: square_a = square_a * square_a ; 6: return( square_a ); 7: } 8: 9: main() { 10: int x, y, result; 11: x = 10; 12: y = 20; 13: square_a = x ; result = square(); x = square_a ; 14: printf("x==%d, result==%d\n", x, result); 15: square_a = y++ ; result = square(); y = square_a ; 16: printf("y==%d, result==%d\n", y, result); 17: }実行結果。
% make square-copy-restore
cc square-copy-restore.c -o square-copy-restore
% ./square-copy-restore
x==100, result==100
y==400, result==400
%
ssize_t read(int fd, void *buf, size_t nbytes)
buf
は、結果を受け取る場所を示したもので、RPCで遠隔に送る意味は
ない。
方法1。インタフェースを変える。
struct read_result_t { ssize_t read_bytes; void *buf; }; read_result_t read(int fd, size_t nbytes)方法2: スタブで違いを吸収する。
ssize_t read(int fd, void *buf, size_t nbytes) { fd, buf(nbytes分), nbytes を整列化する。 サーバへ要求メッセージとして送る。 サーバから応答メッセージを受け取る。 応答メッセージを非整列化して、結果の read_bytes と読んだ内容を取り出す。 読んだ内容を buf read_bytes 分へコピーする。 return read_bytes ; }単純に行えば、上のように余計なコピーが入ることがある。 スタブで最適化すれば、クライアントからサーバへのコピーを減らせる。
図? RPCのバインディング
クライアント側のプログラムとサーバ側のプログラムの対応はもはや1対1で はない。XML-RPC, SOAPなど、テキストを使う RPC もある。