Download presentation
Презентация загружается. Пожалуйста, подождите
1
ネットワーク・プログラミング メッセージの作成とセマフォ
2
全体の位置づけ オペレーションシステム(Linux) ソケットプログラミング プロセス カーネルとシステムコール プロセス間通信 スレッド
クライアントーサーバ 非同期I/Oとマルチタスク
3
1.メッセージの作成 1.1 ASCIIで送信 ASCIIコードで数字を符号化 int型を文字型に変換する。
msgBufferサイズ=depositesの最大サイズ+withdrawalsの最大サイズ+区切りの数(2)+終了を表すNULL(1) #define BUFSIZE 132 char msgBuf[BUFSIZE]; sprintf(msgBuffer, “%d %d “, deposites, withdrawals); send(s, msgBuffer, strlen(msgBuffer), 0); %dと%dの間はスペース(区切り) メッセージだけ送信する (msgBufferのメッセージ以外の領域は送信しない) BUFSIZEと指定 するとゴミが入る deposites スペース withdrawals msgBuffer 49 55 57 57 56 55 50 48 32 52 55 48 51 52 54 49 53 32 ‘1’ ‘7’ ‘9’ ‘9’ ‘8’ ‘7’ ‘2’ ‘0’ ‘ ’ ‘4’ ‘7’ ‘0’ ‘3’ ‘4’ ‘6’ ‘1’ ‘5’ ‘ ’
4
1.2 バイナリで送信 構造体を使う場合 個別に送信する場合 数字をバイナリ(int型)で送信する利点
1.2 バイナリで送信 構造体を使う場合 msgStruct.dep = deposites; msgStruct.wd = withdrawals; send (s, &msgStruct, sizeof (msgStruct), 0); 個別に送信する場合 send (s, &deposites, sizeof (deposites), 0); send (s, &withdrawals, sizeof (withdrawals), 0); 但し、UDPでは2つのパケットになる。 数字をバイナリ(int型)で送信する利点 (一般に)送信データ量が減る。 符号/復号化の手間を省くことが出来る。 数字をバイナリ(int型)で送信する欠点 int型の表現範囲は狭い。 (符号付き整数を2の補数で表す32ビットマシンでは、最大値2,147,483,647) 送信側と受信側で整数フォーマットが一致しない可能性がある。 プロトコルで符号化方法(2の補数、符号と絶対値、符号無し)を統一する必要がある。 構造体 struct{ int dep; int wd; } msgStruct;
5
プロセッサ固有のバイト順とネットワークバイト順が同じならば何もしない
1.3 バイト順 int deposites = ; int withdrawals = ; マシンアーキテクチャ ビッグエンディアン ワード(int型は4バイトが1ワード)の「最上位バイト」が最下位アドレス 68000ファミリ(Motorola社)、sparc(SUN社) リトルエンディアン ワードがビッグエンディアンと逆の順序 x86系(Intel社)、Alpha(DEC社) バイエンディアン 二つのモードを切り替え可能 MIPS、PowerPC(Apple社) データはアドレスの昇順に送信する。 ネットワークバイト順はビッグエンディアン htonl(): 4バイト値をプロセッサ固有からネットワークバイト順に変換。 htons():2バイト値の場合 ntohl(): 4バイト値をネットワークバイト順からプロセッサ固有に変換。 ntohs():2バイト値の場合 ネットワークへの送信順番 アドレス小 アドレス大 ビッグエンディアンのバイト列: 1 18 163 128 2 205 176 247 最上位バイト deposites withdrawals リトルエンディアンのバイト列: 128 163 18 1 247 176 205 2 deposites withdrawals 最上位バイト プロセッサ固有のバイト順とネットワークバイト順が同じならば何もしない msgStruct.dep = htonl(deposites); msgStruct.wd = htonl(withdrawals); send (s, &msgStruct, sizeof (msgStruct),0);
6
2. セマフォによる排他制御 プロセス A プロセス B 1 カーネル semget(); semget(); semop();
2. セマフォによる排他制御 プロセスAとBは、 同じ鍵を持っている プロセス A プロセス B プロセスA semget(); semop(); プロセスB semget(); semop(); プロセス間通信 パイプライン シグナル 共有メモリ メッセージ通信 カーネル セマフォ セマフォ 1 ソケット カーネル 0: 使用中 1: 未使用
7
2.1 セマフォの操作 排他制御 セマフォ操作 排他制御の実施
2.1 セマフォの操作 排他制御 コンピュータ資源(ファイル、メモリ、ディスプレイ等)を複数プロセスが同時に利用することを防ぐこと。 セマフォ操作 アンロック: セマフォ値に+1たす。 ロック: セマフォ値に-1たす。 排他制御の実施 セマフォ値=1(未使用)の時 プロセスはセマフォ値を0にし、資源を使用する。 セマフォ値=0(使用中)の時 プロセスはセマフォ値が1になった時点でセマフォ値を0にし、資源を使用する。 使い終わったら+1たす (アンロック) 使う時 -1たす(ロック) プロセスA プロセスA A使用中 -1 +1 セマフォ 1 セマフォ セマフォ セマフォ 1 セマフォ 初期値=1 待ち解除 1(空き)になるまで待つ B使用中 プロセスB -1 ロック
8
semget セマフォを生成し、識別子を得る
2.2 システムコール semget(): セマフォの生成 key, semflg: 他のIPCと同じ。 nsems: 作成するセマフォ数。 semop(): セマフォの操作 semid: セマフォ識別子 struct sembuf { unsigned short int sem_num short int sem_op; short int sem_flg; } nsops: 操作するセマフォ数 semctl(): セマフォの制御 semnum: セマフォ番号 cmdの種類 IPC_STAT:セマフォ状態を得る IPC_SET:semid_ds構造体の値をセット IPC_RMID:セマフォを削除 GETVAL:セマフォ値を得る SETVAL: セマフォ値をセット semget セマフォを生成し、識別子を得る インクルードファイル #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> 書式 int semget(key_t key, int nsems, int semflg); 戻値 成功時 セマフォ識別子、 失敗時 -1 セマフォの番号 semop セマフォを操作 セマフォ値にたす値。+1又は、-1 インクルードファイル #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> 書式 int semop(int semid, struct sembuf *sops, unsigned int nsops); 戻値 成功時 0、 失敗時 -1 semctl セマフォを制御 インクルードファイル #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> 書式 int semctl(int semid, int semnum, int cmd, …); 戻値 成功時 cmdによって決まる 失敗時 -1 cmdに依存
9
2.3 セマフォを使ったプログラム writer(画面に数字を書く) cleaner(画面の数字を消す) セマフォをロックする。
2.3 セマフォを使ったプログラム writer(画面に数字を書く) セマフォ識別子を獲得する。 以下を繰返す: セマフォをロックする。 画面に数字(0~4)を書く。 セマフォをアンロックする。 cleaner(画面の数字を消す) カーソルを後退し(ランダムな数だけ)数字を消す。 soft2]$ ./seminit soft2]$ ipcs -s セマフォ配列 キー semid 所有者 権限 nsems 状態 0x oida soft2]$ ./writer & ./cleaner [1] 1572 soft2]$ fg ./writer soft2]$ ipcrm sem リソースを削除しました soft2]$ Ctrl-C seminit.c int main() { int semid; key_t semkey; semkey=ftok(“seminit", 'a'); semid=semget(semkey, 1, IPC_CREAT|0666); semctl(semid, 0, SETVAL, 1); return EXIT_SUCCESS; }
10
2.4 画面に数字を書くプログラム writer.c cleaner.c セマフォ識別子を得る ロック操作 ロック操作
2.4 画面に数字を書くプログラム writer.c cleaner.c int main() { int semid; key_t semkey; struct sembuf buf[1]; semkey=ftok("seminit", 'a'); semid=semget(semkey, 1, IPC_CREAT|0666); buf[0].sem_num=0; buf[0].sem_flg=0; while (1) { int i; buf[0].sem_op = -1; semop(semid,buf,1); for (i=0; i<5; i++) { printf("%d",i); fflush(stdout); sleep(1); } buf[0].sem_op = 1; return EXIT_FAILURE; int main() { int semid; key_t semkey; struct sembuf buf[1]; srand(time(NULL)); semkey=ftok("seminit", 'a'); semid=semget(semkey, 1, IPC_CREAT|0666); buf[0].sem_num=0; buf[0].sem_flg=0; while (1) { int i, loop; buf[0].sem_op = -1; semop(semid,buf,1); loop=rand()%5+1; for (i=0; i<loop; i++) { printf("\b \b"); fflush(stdout); sleep(1); } buf[0].sem_op = 1; return EXIT_FAILURE; 乱数のシードを作る (実行する毎に結果が変わる) セマフォ識別子を得る ロック操作 ロック操作 乱数を5で割った余+1 資源 (ディスプレイ) を独占的に使う 後退し、空白を書き、後退する アンロック操作 アンロック操作
11
宿題10 初めにseminitを実行後にhw10とwriterを実行する。 hw10.c:(seminit.cを参考にして)セマフォの値を表示するプログラムを作成せよ。 writerが実行中にセマフォの値が変化する様子を確認せよ。 表紙に氏名と学籍番号を書く 本文にプログラムを書く プログラムの実行結果を書く 実施した内容を説明する文章を書く レポートの締切は次の週の水曜日18:00 端末を二つ( hw10用とwriter用)立ち上げると操作しやすい。 hw10 セマフォ値 writer semctl() 1 1 printf() ロック semctl() アンロック printf() 1
12
宿題10のヒント 1 1 1 hw10 writer ヒント: 1秒毎にセマフォの値を取出す
ヒント: 1秒毎にセマフォの値を取出す 端末を二つ( hw10用とwriter用)立ち上げると操作しやすい。 #include <stdio.h> #include <stdlib.h> #include <sys/ipc.h> #include <sys/sem.h> #include <sys/types.h> int main() { int semid; key_t semkey; int semval; while (1) { semval = semctl(semid, 0, GETVAL); printf("semval=%d\n",semval); sleep(1); } return EXIT_SUCCESS; hw10 セマフォ値 writer semctl() 1 1 printf() ロック semctl() (1)鍵を作成する(writer.cと同様)。 (2)semgetシステムコールを実行し、リターン値をsemidに入れる(writer.cと同様)。 アンロック printf() 1
Similar presentations
© 2024 slidesplayer.net Inc.
All rights reserved.