ネットワーク・プログラミング 1対多のプロセス間通信
全体の位置づけ オペレーションシステム(Linux) ソケットプログラミング プロセス カーネルとシステムコール プロセス間通信 スレッド クライアントーサーバ 非同期I/Oとマルチタスク
1.メッセージ通信 1.1 1対多のプロセス間通信 簡単な残高照会プログラム 残高照会プロセス マスタープロセス 1.メッセージ通信 1.1 1対多のプロセス間通信 口座番号:100 口座番号:102 簡単な残高照会プログラム 預金ファイルにある残高を照会するために二つのプログラムを作成する。 残高照会プロセス 標準入力から入力された口座番号をマスタープロセスへ(キュー1を使って)送信する。 マスタープロセスから(キュー2を使って)受信した残高を標準出力する。 マスタープロセス 口座番号から預金ファイル検索。 口座番号が在れば、残高を返信。 口座番号がなければ、0を送信。 照会プロセス msgsnd(); msgrcv(); 照会プロセス msgsnd(); msgrcv(); 100 785 102 キュー2 キュー1 102 1210 100 マスタープロセス msgrcv(); msgsend(); 預金ファイル
1.2 実行結果 [oida@rpc261 soft2]$ gcc -o shokai shokai.c 1.2 実行結果 [oida@rpc261 soft2]$ gcc -o shokai shokai.c [oida@rpc261 soft2]$ gcc -o master master.c [oida@rpc261 soft2]$ cat > yokinfile 100 1210 101 2000 102 785 103 50 [oida@rpc261 soft2]$ ./master & [3] 12182 [oida@rpc261 soft2]$ ./shokai Enter number: 101 Zandaka= 2000 Enter number: 103 Zandaka= 50 [oida@rpc261 soft2]$ ipcs -q ------ メッセージキュー -------- キー msqid 所有者 権限 使用バイト数 メッセージ 0x610180a1 327680 oida 666 0 0 0x7a018093 360449 oida 666 0 0 [oida@rpc261 soft2]$ fg ./master [oida@rpc261 soft2]$ ipcrm msg 327680 360449 リソースを削除しました [oida@rpc261 soft2]$ 預金ファイルyokinfileに書込まれる口座番号と預金残高。キーボードから入力する。 masterをバックグラウンドで実行 使い終えたメッセージキューの削除 口座番号(103)を入力すると預金残高(50)が表示される
msgget メッセージキューを生成し、識別子を得る 1.3 メッセージ通信 msgget メッセージキューを生成し、識別子を得る メッセージ送信(msend.c) メッセージキューを生成しその識別子を得る。 メッセージを送信する。 メッセージ受信(mrecv.c) 受信したいメッセージが入っているメッセージキューの識別子を得る。 メッセージを受信する。 メッセージの構造体 struct msgbuf { long mtypes; char mtext[MSG_SIZ]; }; システムコールの引数 msgsz: 配列 mtext の大きさ msgtyp: 受信したいメッセージタイプ(mtypes)を指定する。 msgflg: IPC_NOWAITを設定すると、メッセージキューにメッセージが無い時、エラーを返す 。 上記以外はメッセージが到着するまで待つ。 インクルードファイル #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> 書式 int msgget(key_t key, int msgflg); 戻値 成功時 メッセージ識別子、 失敗時 -1 msgsnd メッセージを送信する インクルードファイル #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> 書式 int msgsnd(int msgid, struct msgbuf *msgp, size_t msgsz, int msgflg); 戻値 成功時 0、 失敗時 -1 利用者が設定 msgrcv メッセージを受信する インクルードファイル #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> 書式 ssize_t msgrcv(int msgid, struct msg buf *msgp, size_t msgsz, long msgtyp, int msgflg); 戻値 成功時 mtext配列にコピーしたバイト数 失敗時 -1 msgrcvの場合
1.4 残高照会プログラム shokai.c master.c int main() { struct msgbuf { 1.4 残高照会プログラム shokai.c master.c int main() { struct msgbuf { long mtype; char mtext[256]; }; char line[256]; int msqid1, msqid2; key_t msgkey1, msgkey2; struct msgbuf recv, send; msgkey1=ftok("master",'a'); msgkey2=ftok("shokai",'z'); msqid1=msgget(msgkey1,IPC_CREAT|0666); msqid2=msgget(msgkey2,IPC_CREAT|0666); printf("Enter number: "); fgets(line,sizeof(line),stdin); if (sscanf(line,"%ld", &send.mtype)==1) { msgsnd(msqid1,&send,sizeof(send.mtext),0); msgrcv(msqid2,&recv,sizeof(recv.mtext),send.mtype,0); printf("Zandaka= %s\n",recv.mtext); } return EXIT_SUCCESS; int main() { struct msgbuf { long mtype; char mtext[256]; }; int msqid1, msqid2; int searchdata(long key, char *dp, int size); key_t msgkey1, msgkey2; struct msgbuf recv, send; msgkey1=ftok("master",'a'); msgkey2=ftok("shokai",'z'); msqid1=msgget(msgkey1,IPC_CREAT|0666); msqid2=msgget(msgkey2,IPC_CREAT|0666); while(1) { msgrcv(msqid1,&recv,sizeof(recv.mtext),0,0); if (searchdata(recv.mtype,send.mtext, sizeof(send.mtext))==EOF) { snprintf(send.mtext,sizeof(send.mtext),"%ld",0L); } send.mtype=recv.mtype; msgsnd(msqid2,&send,sizeof(send.mtext),0); return EXIT_SUCCESS; 口座番号に対する 残高を検索 mtypeは口座番号 long型の0 自分の口座番号のメッセージを取出す
ファイルから1行読込み、lineに入れる。 ポインタ変数dpから始まる領域にydataをコピー 1.5 残高照会プログラム 関数 searchdata() int searchdata(long key,char *dp,int size) { FILE *p; long ydata,ynum; char line[256]; p=fopen("yokinfile","r"); while(fgets(line,sizeof(line),p)!=NULL) { if (sscanf(line,"%ld%ld",&ynum,&ydata)==2) { if (key==ynum) { snprintf(dp,size,"%ld",ydata); fclose(p); return 0; } return EOF; ファイルから1行読込み、lineに入れる。 ynumとydataに値が代入された ポインタ変数dpから始まる領域にydataをコピー
宿題15 プログラミングスキル確認 表紙に氏名と学籍番号を書く 本文にプログラムを書く プログラムの実行結果を書く 宿題15 プログラミングスキル確認 (shokai.c, master.c, TCPEchoClient.c,TCPEchoServer.c, HandleTCPClient.c, DieWithError.cを参考にして)HandleTCPClient.cを修正してソケットを使った残高照会プログラムhw15.cを作成せよ。 表紙に氏名と学籍番号を書く 本文にプログラムを書く プログラムの実行結果を書く レポートの締切は来週の水曜日18:00
宿題15 ヒント TCPEchoClient hw15 hw15.c 口座番号 預金残高 宿題15 ヒント TCPEchoClient hw15 口座番号 hw15.c #include <stdio.h> /* for printf() and fprintf() */ #include <sys/socket.h> /* for recv() and send() */ #include <unistd.h> /* for close() */ #include <string.h> #define RCVBUFSIZE 32 /* Size of receive buffer */ int searchdata(long key, char *dp, int size); long id; void DieWithError(char *errorMessage); /* Error handling function */ void HandleTCPClient(int clntSocket) { /* ここに何を書かなければいけないか、考えてください */ } 関数searchdata(long key, char *dp, int size) を最後に追加する。 預金残高 [oida@rpc261 socket]$ gcc -o hw15 hw15.c TCPEchoServer.c DieWithError.c [oida@rpc261 socket]$ ./hw15 5000 & [1] 1852 [oida@rpc261 socket]$ cat yokinfile 100 1210 101 2000 102 785 103 5000 [oida@rpc261 socket]$ ./TCPEchoClient aaa.bbb.ccc.ddd "101" 5000 Handling client aaa.bbb.ccc.ddd Received: 2000 [oida@rpc261 socket]$ ./TCPEchoClient aaa.bbb.ccc.ddd "100" 5000 Received: 1210 [oida@rpc261 socket]$ ./TCPEchoClient aaa.bbb.ccc.ddd "103" 5000 Received: 5000 [oida@rpc261 socket]$ fg ./hw15 5000 [oida@rpc261 socket]$ aaa.bbb.ccc.dddはIPアドレスを表す 口座103の残高は5000