情報学類 分散システム 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 もある。