情報学類 分散システム 2009年01月13日
筑波大学システム情報工学研究科
コンピュータサイエンス専攻, 電子・情報工学系
新城 靖
<yas@is.tsukuba.ac.jp>
このページは、次の URL にあります。
http://www.coins.tsukuba.ac.jp/~yas/coins/dsys-2008/2009-01-13
あるいは、次のページから手繰っていくこともできます。
http://www.coins.tsukuba.ac.jp/~yas/
http://www.cs.tsukuba.ac.jp/~yas/
rpcgen
というコマンド。
rpcgen コマンドを使うには、次のようなファイルを作成する。

図? rpcgenによるRPCプログラム開発で利用するファイル
name.x
name_client.c
name_server.c
% rpcgen name.x
次の4つのファイルが生成される。
name.h
name_clnt.c
name_xdr.c
name.x で定義したデータ構造について、
XDR
のための手続き(整列化と非整列化を行なう手続き) 。
クライアント側とサーバ側の両方で使われる。
name_svc.c
/etc/rpc
にある。
SunRPCでは, 最終的にはTCP/IPまたはUDP/IPでデータが送られる。プログラム 番号などTCP/IPまたはUDP/IPのポート番号を対応させる必要がある。
各ホストには
portmap (portmapper)
というサーバがいて、3つ組
portmap の情報は、
rpcinfo
コマンドで表示できる。
% rpcinfo -p
program vers proto port
100000 2 tcp 111 portmapper
100000 2 udp 111 portmapper
100007 2 tcp 1024 ypbind
100007 2 udp 1027 ypbind
100007 1 tcp 1024 ypbind
100007 1 udp 1027 ypbind
100005 1 udp 831 mountd
100005 2 udp 831 mountd
100005 1 tcp 834 mountd
100005 2 tcp 834 mountd
100003 2 udp 2049 nfs
100001 2 udp 4193 rstatd
100001 3 udp 4193 rstatd
100001 4 udp 4193 rstatd
%
他のホストの情報も調べられる。
% rpcinfo -p hostname
サーバは、起動時に、portmap に登録する。
bool_t pmap_set(program, version, protocol, port) u_long program; u_long version; int protocol; u_short port;クライアントは、呼び出す前に、ポート番号を調べる。
u_short pmap_getport(address, program, version, protocol) struct sockaddr_in *address; u_long program; u_long version; u_int protocol;
スタブが自動的に呼び出すので、普段は気にすることはない。
portmap 自身も RPC で動いている。portmap の自身のポート番号は、111 と 決まっている。
int get_highscore_client_rpc( char *server,score_record_t records[], int len )
score_record_t型)を最大 len 個だけ取得する。
実際に保存していた数を返す。
int put_score_client_rpc( char *server, int score, char *name )
.」を忘れないように。
% mkdir hiscore-rpc
% cd hiscore-rpc
% cp ~yas/dsys/highscore/rpc/add-hiscore-rpc.c .
% cp ~yas/dsys/highscore/rpc/highscore_rpc-client.c .
% cp ~yas/dsys/highscore/rpc/highscore_rpc-server.c .
% cp ~yas/dsys/highscore/rpc/highscore_rpc.x .
% cp ~yas/dsys/highscore/rpc/show-hiscore-rpc.c .
% cp ~yas/dsys/highscore/rpc/Makefile .
% ls
Makefile highscore_rpc-client.c highscore_rpc.x
add-hiscore-rpc.c highscore_rpc-server.c show-hiscore-rpc.c
% make
rpcgen highscore_rpc.x
cc -g -DRPC_SVC_FG -c -o add-hiscore-rpc.o add-hiscore-rpc.c
cc -g -DRPC_SVC_FG -c -o highscore_rpc-client.o highscore_rpc-client.c
cc -g -DRPC_SVC_FG -c -o highscore_rpc_clnt.o highscore_rpc_clnt.c
<警告略>
cc -g -DRPC_SVC_FG -c -o highscore_rpc_xdr.o highscore_rpc_xdr.c
cc -g -DRPC_SVC_FG add-hiscore-rpc.o highscore_rpc-client.o highscore_rpc_clnt.o highscore_rpc_xdr.o -o add-hiscore-rpc
cc -g -DRPC_SVC_FG -c -o show-hiscore-rpc.o show-hiscore-rpc.c
cc -g -DRPC_SVC_FG show-hiscore-rpc.o highscore_rpc-client.o highscore_rpc_clnt.o highscore_rpc_xdr.o -o show-hiscore-rpc
cc -g -DRPC_SVC_FG -c -o highscore_rpc-server.o highscore_rpc-server.c
cc -g -DRPC_SVC_FG -c -o highscore_rpc_svc.o highscore_rpc_svc.c
cc -g -DRPC_SVC_FG -c -o highscore_rpc_clnt.o highscore_rpc_clnt.c
<警告略>
cc -g -DRPC_SVC_FG highscore_rpc-server.o highscore_rpc_svc.o highscore_rpc_xdr.o -o highscore_rpc-server
% ls
Makefile highscore_rpc-server.c highscore_rpc_svc.o
add-hiscore-rpc highscore_rpc-server.o highscore_rpc_xdr.c
add-hiscore-rpc.c highscore_rpc.h highscore_rpc_xdr.o
add-hiscore-rpc.o highscore_rpc.x show-hiscore-rpc
highscore_rpc-client.c highscore_rpc_clnt.c show-hiscore-rpc.c
highscore_rpc-client.o highscore_rpc_clnt.o show-hiscore-rpc.o
highscore_rpc-server highscore_rpc_svc.c
%
make コマンドを実行すると、Makefile の記述に従い3つの実行
形式のファイル highscore_rpc-server,
add-hiscore-rpc, add-hiscore-rpc が作られる。
自動生成されたファイル highscore_rpc_clnt.c と
highscore_rpc_svc.c をコンパイルする時に警告(warning)が表示され
るが、問題はない。
例題を実行するには、クライアント用とサーバ用に端末を2つ開く。
その方法は、make help で表示される。
% make help
Open two terminals for server and client
server:
./highscore-server
(To stop this server, Press ^C)
client:
./add-hiscore-rpc server score name
./show-hiscore-rpc server num
%
クライアントとサーバは、別のコンピュータで動作させても良い。 以下の例では、サーバをazalea20 で動作させている。 サーバ側:
% ssh azalea20
% cd hiscore-rpc/
% ./highscore_rpc-server
サーバは終了しないので、実験が終わったら ^C で止める。
クライアント側は、もう1つの端末で実行する。
rpcinfo コマンドで、サーバのプログラム番号、プロトコルポート番号
を確認する。
% rpcinfo -p azalea20
program vers proto port
100000 2 tcp 111 portmapper
100000 2 udp 111 portmapper
100024 1 udp 1013 status
100024 1 tcp 1006 status
100021 0 udp 1000 nlockmgr
100021 1 udp 1000 nlockmgr
100021 3 udp 1000 nlockmgr
100021 4 udp 1000 nlockmgr
100021 0 tcp 1005 nlockmgr
100021 1 tcp 1005 nlockmgr
100021 3 tcp 1005 nlockmgr
100021 4 tcp 1005 nlockmgr
537000100 1 udp 49202
537000100 1 tcp 50471
%
537000100 は、16進数で0x2001f8a4。
クライアントを実行する。
% ./add-hiscore-rpc
Usage: % ./add-hiscore-rpc server score "User Name"
% ./add-hiscore-rpc azalea20 10 "Yasushi Shinjo"
% ./add-hiscore-rpc azalea20 20 "Kazuhiko Kato"
% ./show-hiscore-rpc
Usage: % ./show-hiscore-rpc host n
% ./show-hiscore-rpc azalea20 10
2 hiscore record(s) received
20 Kazuhiko Kato
10 Yasushi Shinjo
%
実験が終了したら、サーバを ^C コマンドで削除する。
% ./highscore_rpc-server
^C
%
1:
2: /*
3: highscore_rpc.h -- Hiscore Protocol over SunRPC
4: Created on: 2008/12/23 14:19:17
5: ~yas/dsys/highscore/rpc/highscore_rpc.x
6: */
7:
8: const HIGHSCORE_MAX_RECORDS = 10;
9: const HIGHSCORE_NAME_LEN = 28;
10:
11: struct score_record {
12: int score;
13: opaque name[HIGHSCORE_NAME_LEN];
14: };
15: typedef struct score_record score_record_t;
16:
17: struct get_highscore_result_t {
18: score_record records<HIGHSCORE_MAX_RECORDS>;
19: };
20:
21: program HIGHSCORE_RPC_PROG {
22: version HIGHSCORE_RPC_VERSION {
23: get_highscore_result_t GET_HIGHSCORE(int) = 1 ;
24: int PUT_SCORE(score_record_t) = 2 ;
25: } = 1;
26: } = 0x2001f8a4 ;
27:
28: #ifdef RPC_HDR
29: %extern int get_highscore_client_rpc( char *server,
30: % score_record_t records[], int len );
31: %extern int put_score_client_rpc(char *server, int score, char *name);
32: #endif
23-24行目が手続きの定義。
GET_HIGHSCORE
PUT_SCORE
が手続きの名前(手続き番号を示す定数の定義)。
GET_HIGHSCOREの引数は、int 型、結果は、
get_highscore_result_t
型。SunRPC では、基本的には引数も結果も1つずつ。複数必要な時には、構造体を
定義する。
手続きの定義を program 番号と
version 番号の括弧が取り囲んでいる。
const は、定数の定義。
% は、そのまま生成されるファイルにコピーされることを意味する。
この場合は、RPC_HDR で取り囲み、.h にだけコピーされる。
このプログラムには、2種類の配列が使われている。
[]
<>
opaque (不定形)は、バイトを意味する。char の場合、
「文字」としてコード変換がおそなわれるので遅くなる。
ヘッダファイルの主要部分は、以下の通りである。
13: #define HIGHSCORE_MAX_RECORDS 10
14: #define HIGHSCORE_NAME_LEN 28
16: struct score_record {
17: int score;
18: char name[HIGHSCORE_NAME_LEN];
19: };
20: typedef struct score_record score_record;
30: typedef score_record score_record_t;
40: struct get_highscore_result_t {
41: struct {
42: u_int records_len;
43: score_record *records_val;
44: } records;
45: };
46: typedef struct get_highscore_result_t get_highscore_result_t;
55: extern int get_highscore_client_rpc( char *server,
56: score_record_t records[], int len );
57: extern int put_score_client_rpc(char *server, int score, char *name);
59: #define HIGHSCORE_RPC_PROG ((u_long)0x2001f8a4)
60: #define HIGHSCORE_RPC_VERSION ((u_long)1)
71: #define GET_HIGHSCORE ((u_long)1)
72: extern get_highscore_result_t * get_highscore_1(int *, CLIENT *);
73: extern get_highscore_result_t * get_highscore_1_svc(int *, struct svc_req *);
74: #define PUT_SCORE ((u_long)2)
75: extern int * put_score_1(score_record_t *, CLIENT *);
76: extern int * put_score_1_svc(score_record_t *, struct svc_req *);
元のインタフェース記述とよく似ている。
可変長の配列が、構造体として表現されている。
opaque は、char として出力されている。
put_score_client_rpc() 関数を呼び出す簡単なプログラム。
1:
2: /*
3: add-hiscore-rpc.c -- The main function of put_score_client_rpc().
4: Created on: 2009/01/06 18:07:37
5: ~yas/dsys/highscore/rpc/add-hiscore-rpc.c
6: */
7:
8: #include <stdio.h> /* stderr, fprintf() */
9: #include <stdlib.h> /* strtol() */
10: #include "highscore_rpc.h"
11:
12: void usage( char *comname ) {
13: fprintf(stderr,"Usage: %% %s server score \"User Name\"\n", comname);
14: exit( 1 );
15: }
16:
17: main( int argc, char *argv[], char *envp[] ) {
18: int score, portno ;
19: char *name, *server ;
20: if( argc != 4 )
21: usage( argv[0] );
22: server = argv[1];
23: score = strtol( argv[2], 0, 10);
24: name = argv[3];
25: put_score_client_rpc( server, score, name );
26: }
put_score_client()関数を呼び出す。
get_hiscore_client_rpc() 関数を呼び出す簡単なプログラム。
1:
2: /*
3: show-hiscore-rpc.c -- The main function for get_highscore_client_rpc().
4: Created on: 2009/01/09 01:21:49
5: ~yas/dsys/highscore/rpc/show-hiscore-rpc.c
6: */
7:
8: #include <stdio.h> /* stderr, fprintf() */
9: #include <stdlib.h> /* strtol() */
10: #include "highscore_rpc.h"
11:
12: static void show_score( char *host, int top );
13:
14: static void usage( char *comname ) {
15: fprintf(stderr,"Usage: %% %s host n\n", comname);
16: exit( 1 );
17: }
18:
19: main( int argc, char *argv[], char *envp[] ) {
20: int top ;
21: char *name, *server ;
22: if( argc != 3 )
23: usage( argv[0] );
24: server = argv[1];
25: top = strtol( argv[2], 0, 10);
26: show_score( server, top );
27: }
28:
29: static void show_score( char *server, int top ) {
30: score_record_t records[HIGHSCORE_MAX_RECORDS];
31: int n, i ;
32: if( top > HIGHSCORE_MAX_RECORDS ) {
33: fprintf(stderr,"Warning: top too large: %d\n",top);
34: top = HIGHSCORE_MAX_RECORDS;
35: }
36: n = get_highscore_client_rpc( server, records, top );
37: if( n >= 0 ) {
38: printf("%d hiscore record(s) received\n", n );
39: for( i=0; i<n; i++ ) {
40: printf("%10d %s\n", records[i].score, records[i].name );
41: }
42: }
43: else {
44: printf("error: %d\n", n );
45: }
46: }
put_score_client_rpc()関数を呼び出す。
1: 2: /* 3: highscore_rpc-client.c -- The hiscore client using SunRPC. 4: Created on: 2009/01/06 18:10:11 5: ~yas/dsys/highscore/rpc/highscore_rpc-client.c 6: */ 7: 8: #include <stdio.h> /* stderr, fprintf() */ 9: #include <string.h> /* memset() */ 10: #include "highscore_rpc.h" 11:
12: int get_highscore_client_rpc( char *server,
13: score_record_t records[], int len ) {
14: CLIENT *clnt;
15: get_highscore_result_t *result;
16: int *arg, n, i;
17: clnt = clnt_create(server,HIGHSCORE_RPC_PROG,
18: HIGHSCORE_RPC_VERSION, "tcp");
19: if( clnt == NULL ) {
20: clnt_pcreateerror( server );
21: goto error0;
22: }
23: arg = &len;
24: result = get_highscore_1( arg,clnt );
25: if( result == NULL ) {
26: clnt_perror( clnt, "call failed:" );
27: goto error1;
28: }
29: n = result->records.records_len ;
30: if( n > len ) {
31: fprintf(stderr,"received message too large: %d > %d\n", n, len );
32: goto error1;
33: }
34: for( i=0 ; i<n; i++ ) {
35: records[i] = result->records.records_val[i];
36: }
37: xdr_free( (xdrproc_t)xdr_get_highscore_result_t, (char *)result );
38: clnt_destroy( clnt );
39: return( n );
40:
41: error1: clnt_destroy( clnt );
42: error0: return( -1 );
43: }
44:
この関数の中心部分は、自動生成されたスタブ get_highscore_1() を呼び出す部分である。
引数は、インタフェースで定義された型 intへのポインタと、
CLIENT 構造体へのポインタ、
結果は、インタフェースで定義された構造体
get_highscore_result_tへのポインタである。
スタブget_highscore_1() は、rpcgen が生成する
*_clnqt.c というファイルに含まれてる。これは、引数をマーシャリ
ングして要求メッセージを組み立て、サーバに送信する。サーバから応答メッ
セージを受け取り、アンマーシャリングして、結果として返す。アンマーシャ
リングの時、結果を保持するメモリを、malloc() で確保している。
clnt_create() は、CLIENT 構造体を確保する。
引数は、サーバのホスト名、
プログラム番号、
バージョン番号、
通信に使うプロトコルである。
使い終わった構造体は、clnt_destroy() で解放する。
結果 result は、可変長の配列である。
result->records.records_len には、可変長配列の要素数、
result->records.records_val[i] には、可変長配列のi番目の要素
が含まれている。
ループして、その可変長配列から引数で与えられた配列にコピーしている。
xdr_free() で、アンマーシャリングの時に確保したメモリを解放している。
内部では、free() が呼ばれている。
TCP版と異なり、マーシャリング、メッセージの送受信のコードが含まれていない。
45: int put_score_client_rpc( char *server, int score, char *name ) {
46: CLIENT *clnt;
47: score_record_t arg;
48: int *result, ok;
49: clnt = clnt_create( server,HIGHSCORE_RPC_PROG,
50: HIGHSCORE_RPC_VERSION, "tcp");
51: if( clnt == NULL ) {
52: clnt_pcreateerror( server );
53: goto error0;
54: }
55: arg.score = score;
56: memset( arg.name, 0, HIGHSCORE_NAME_LEN );
57: snprintf( arg.name, HIGHSCORE_NAME_LEN, "%s", name );
58: result = put_score_1( &arg, clnt );
59: if( result == NULL ) {
60: clnt_perror( clnt, "call failed:" );
61: goto error1;
62: }
63: ok = *result;
64: xdr_free( (xdrproc_t)xdr_int, (char *)result );
65: clnt_destroy( clnt );
66: return( ok );
67:
68: error1: clnt_destroy( clnt );
69: error0: return( -1 );
70: }
この関数の中心部分は、自動生成されたスタブ put_score_1() を呼び出す部分である。
1:
2: /*
3: highscore_rpc-server.c -- The hiscore server using SunRPC.
4: Created on: 2009/01/09 01:31:49
5: ~yas/dsys/highscore/rpc/highscore_rpc-server.c
6: */
7:
8: #include <stdio.h> /* stderr, fprintf() */
9: #include <stdlib.h> /* strtol() */
10: #include <string.h> /* memcpy() */
11: #include "highscore_rpc.h"
12:
13: /* Hiscore data in memory */
14: static score_record_t hiscore_records[HIGHSCORE_MAX_RECORDS];
15: static int hiscore_nelements;
16:
17: static void hiscore_server( int portno );
18: static void hiscore_request_reply( int com );
19: static int insert_score( score_record_t records[], int len, int nelement,
20: int score, char *user );
21: static int find_posision( score_record_t records[], int len, int nelement,
22: int score );
23:
24: get_highscore_result_t *
25: get_highscore_1_svc( int *argp, struct svc_req *rqstp ) {
26: static get_highscore_result_t result;
27: int len,i,n ;
28: xdr_free( (xdrproc_t)xdr_get_highscore_result_t, (char *)&result );
29: len = *argp;
30: if( len > HIGHSCORE_MAX_RECORDS )
31: len = HIGHSCORE_MAX_RECORDS;
32: n = len < hiscore_nelements ? len : hiscore_nelements ;
33: /* return n and hiscore_records[0..n-1] to client. */
34: result.records.records_len = n ;
35: result.records.records_val = malloc( sizeof(score_record_t)*n );
36: if( result.records.records_val == NULL )
37: {
38: fprintf( stderr,"highscore_rpc-server: no memory\n" );
39: result.records.records_len = 0;
40: goto error0;
41: }
42: for( i=0 ; i<n ; i++ ) {
43: result.records.records_val[i] = hiscore_records[i];
44: }
45: error0: return( &result );
46: }
47:
48: int *put_score_1_svc( score_record_t *argp, struct svc_req *rqstp ) {
49: static int result;
50: /* xdr_free( (xdrproc_t)xdr_int, (char *)&result ); *//* Not needed. */
51: hiscore_nelements =
52: insert_score( hiscore_records, HIGHSCORE_MAX_RECORDS,
53: hiscore_nelements, argp->score, argp->name );
54: return( &result );
55: }
56:
57: static int insert_score( score_record_t records[], int len, int nelement,
58: int score, char *user ) {
...
75: static int find_posision( score_record_t records[], int len, int nelement,
76: int score ) {
...
サーバ側では、手続き get_highscore_1_svc() と
put_score_1_svc() を記述する。
引数と結果は、rpcgen のソースで定義した構造体へのポインタ。
結果を返す時の構造体へのポインタを返す方法が問題。自動変数(auto 変数) にすると、呼出し側に戻った瞬間に無効になる。よく使われるのは、静的変数 (static 変数)に結果を代入して、返すことだが、マルチスレッドプログラミ ングでは問題になる。
malloc() で動的にメモリを確保している。このメモリは、
xdr_free() で解放される。
サーバ側の main() 関数は、rpcgen により
自動生成される。このmain()では、
ポートマッパ(port mapper)
へのプログラム番号とバージョン番号の登録される。
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 。
Sunの技術で、構造体をファイルに保存することができる。
構造体を整列化し、他のプロセスに通信メッセージとして送る代わりにファイ ルに保存する。
SunRPCでは、xdrstdio_create() という関数が用意されている。 ストリーム入出力(FILE *) に対して構造体を読み書きすることができるようになる。
RPCと同様に、構造体にポインタが含まれていた場合、再帰的にファイルに保 存される。異なる機種で読み出すことができる。
.x ファイルに記述する。
enum intstack_error {
INTSTACK_OK = 0,
INTSTACK_OVERFLOW = 1,
INTSTACK_UNDERFLOW = 2
};
struct pop_result {
int data;
int error;
};
program INTSTACK_PROG {
version INTSTACK_VERSION {
intstack_error PUSH(int) = 11 ;
pop_result POP(void) = 12 ;
} = 1 ;
} = 0x20051002 ;
#define STACKSIZE 10 int stack[STACKSIZE]; int sp=STACKSIZE; // 後ろから使う時。前から使う方法もある。
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 INIT(void) = 10 ;
int PUT(keyvalue_t) = 11 ;
int GETVALUE(key_t) = 12 ;
} = 1 ;
} = 0x20051001 ;
サーバ側では、hcreate(), hsearch() 等のライブラリ関数を用いてもよい。
注意:putenv() の引数は、strdup() すること。(同じ名前の環境変数がある と、ゴミが出てきてしまうが、この課題では問題ないとする。)
~yas/coins/dsys-2008/nfs/fh/dir1.fh
(~yas/coins/dsys-2008/nfs/dir1)
~yas/coins/dsys-2008/nfs/fh/dir2.fh
(~yas/coins/dsys-2008/nfs/dir2)
~yas/coins/dsys-2008/nfs/fh/dir3.fh
(~yas/coins/dsys-2008/nfs/dir3)
~yas/coins/dsys-2008/nfs/fh/file1.fh
(~yas/coins/dsys-2008/nfs/dir4/file1)
~yas/coins/dsys-2008/nfs/fh/file2.fh
(~yas/coins/dsys-2008/nfs/dir4/file2)
~yas/coins/dsys-2008/nfs/fh/file3.fh
(~yas/coins/dsys-2008/nfs/dir4/file3)
まず、次のような「テキストファイル」を作成する。漢字コードとしては、 JIS、Shift-JIS、EUC を受け付ける。(PDF, RTF, ワープロの文書ファイルで は受付ない。テキストでも Unicode (UTF) は、受け付けない。ZIP や tar, gzip 等で固めたり圧縮しないように。)
---------------------------------------------------------------------- 学籍番号: 200604321 名前: 漢字の名前 課題番号:M 練習問題番号:N 題名:subject <内容> ----------------------------------------------------------------------本文の先頭に学籍番号と名前(漢字の名前がある人は、漢字で)を書きなさい。 課題番号としては、「1」 と記述しなさい。 練習問題番号とは「★練習問題」に続いて表示されている番号である。 題名には、電子メールの Subject: と同様に、内容に即したものをつける。
<内容>は、日本語(または英語)で書きなさい。文章には、述語を付ける。 体言止めは、使ってはならない。単にプログラムを含めるのではなく、「以下 に○○のプログラムを示す」と書くこと。<内容>には、プログラムだけでな く、実行結果(入力と出力)と説明をつける。
問題を難しい方に変えてた場合、または、最初から難しい問題を解いた場合に は、<内容>の部分で主張しなさい。
作成したファイルを、次のページから投稿する。
上で書いた課題番号、題名を繰り返し指定する。さらに、WWW ブラウザの機能 を使って作成したレポートのファイルを選択する。 最後に、「提出」ボタンを押す。
提出されたレポートは、次のボタンで表示できます。
もし、提出に失敗したり、提出には成功しても確認画面に現れない場合には、 新城(yas@is.tsukuba.ac.jp)かTAに、連絡しなさい。
レポートを再提出する時には、どの部分を修正したのかが簡単にわかるように 説明しなさい。
提出したレポートは、講義が終るまで保存しなさい。