情報学類 分散システム 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: #endif23-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に、連絡しなさい。
レポートを再提出する時には、どの部分を修正したのかが簡単にわかるように 説明しなさい。
提出したレポートは、講義が終るまで保存しなさい。