システムプログラミング 第12回 プロセス間通信 情報工学科 篠埜 功.

Slides:



Advertisements
Similar presentations
システムプログラミング 第11回 シグナル 情報工学科 篠埜 功. 今回の内容 前回の補足( exit システムコールについ て) プロセス間通信 – シグナルの送信 --- 今回の内容 – パイプによる通信 – ソケットによる通信.
Advertisements

システムプログラミング 情報工学科 篠埜 功 情報工学科 3 年生対象 専門科目 第5回 シェルスクリプトの続 き レポート課題 main 関数の引数 usage メッセージ.
ネットワーク・プログラミ ング カーネルの役割とプロセス生成. 1.1 OS の役割 仮想マシン OS はハードウェアの多様性 をカプセル化し、利用者を 複雑な処理から開放する。 プロセス管理 時間多重化により各プロセ スに CPU を割当てる。 メモリ管理 メモリ空間の多重化により、 各プロセスにメモリを割当.
プロセスの生成とコマンドの実行 プロセスの生成とコマンドの実行 プロセス生成のシステムコール プロセス生成のシステムコール プロセス生成のプログラム例 プロセス生成のプログラム例 プログラム実行のシステムコール プログラム実行のシステムコール 子プロセスの終了を待つシステムコール 子プロセスの終了を待つシステムコール.
システムプログラミング 第10回 情報工学科 篠埜 功. 今回の内容 プロセス(続き) – execve システムコール 現在のプロセスを、引数に与えられたファイル(実行 形式ファイルあるいはシェルスクリプト等の実行可能 なファイル)を受け取り、現在のプログラムをそれで 置き換える(変身)。 fork.
システムプログラミング 第7回、8回 ファイルシステム関連の システムコール
システムプログラミング 第6回、7回 main関数の引数 usageメッセージ システムコールのエラーメッセージ ファイル
数理情報工学演習第一C プログラミング演習 (第3回 ) 2014/04/21
プログラミング入門2 第10回 動的な領域確保 情報工学科 篠埜 功.
プログラミング入門2 第10回 構造体 情報工学科 篠埜 功.
プログラミング入門2 第10回 構造体 情報工学科 篠埜 功.
ネットワークプログラミング 第7回「ネットワークとプログラミング(2)」
リダイレクト パイプ 標準入出力プログラム コマンド行引数 関数 system()
システムプログラミング 第5回 情報工学科 篠埜 功 ヒアドキュメント レポート課題 main関数の引数 usageメッセージ
システムプログラミング 第13回 情報工学科 篠埜 功.
ネットワークプログラミング 第9回「応用ネットワークプログラミング(1)」
システムプログラミング 第11回 シグナル 情報工学科  篠埜 功.
OSとコマンド OS:コンピュータを使うための基本プログラム コマンド:OS上で使用できる命令 OS本体であるカーネルの内部コマンド
第8回ネットワークプログラミング 中村 修.
担当:青木義満 情報工学科 3年生対象 専門科目 システムプログラミング システムプログラミング プロセス間通信(パイプ) 担当:青木義満
アルゴリズムとデータ構造 補足資料6-3 「サンプルプログラムcat3.c」
担当:青木義満、篠埜 功 情報工学科 3年生対象 専門科目 システムプログラミング 第8回、第9回 シグナル処理 担当:青木義満、篠埜 功
システムプログラミング 第11回 シグナル 情報工学科  篠埜 功.
精密工学科プログラミング基礎 第9回資料 (12/11 実施)
情報工学科 3年生対象 専門科目 システムプログラミング 第5回、第6回 ヒアドキュメント レポート課題 情報工学科 篠埜 功.
システムプログラミング 第13回 プロセス間通信(続き) 情報工学科 篠埜 功.
UDPエコーサーバ UDP-echoサーバのプログラムモデル(Cプログラム) サーバで利用するソケット関数(Cプログラム)
システムプログラミング 第13回 情報工学科 篠埜 功.
システムプログラミング 第6回、7回、8回 情報工学科 篠埜 功.
システムプログラミング 第9回 、10回 ハードリンク、シンボリックリンク プロセスの生成
ファイル入出力と プロセス間通信 (2) 2004年12月16日 海谷 治彦.
システムプログラミング 第12回 プロセス間通信 情報工学科 篠埜 功.
マルチスレッド処理 マルチプロセス処理について
岡村耕二 トランスポート層 ソケットプログラミング 岡村耕二 情報ネットワーク.
リダイレクト パイプ 標準入出力プログラム コマンド行引数 関数 system()
ユビキタスシステムアーキテクチャ 第5回 ネットワークプログラミングの基礎
プログラミング入門2 第11回 情報工学科 篠埜 功.
演習1の解答例の解説 2004年10月21日 海谷 治彦.
プログラミング入門2 第11回 情報工学科 篠埜 功.
ネットワークプログラミング (5回目) 05A1302 円田 優輝.
Webプロキシ HTTP1.0 ヒント CS-B3 ネットワークプログラミング  &情報科学科実験I.
演習1の解答例の解説 2006年11月8日 海谷 治彦.
担当:青木義満 情報工学科 3年生対象 専門科目 システムプログラミング 第6回 システムプログラミング概要 プロセスの生成 担当:青木義満
岡村耕二 トランスポート層 岡村耕二 情報ネットワーク.
システムプログラミング 第7回、8回 ファイルシステム関連の システムコール
ネットワーク・プログラミング ソケットオプションとスレッド.
岡村耕二 トランスポート層 岡村耕二 情報ネットワーク.
2005年度 データ構造とアルゴリズム 第6回 「ハッシュ法を用いた探索」
精密工学科プログラミング基礎Ⅱ 第4回資料 今回の授業で習得してほしいこと: 文字列の扱い ファイル入出力の方法 コマンドライン引数の使い方
C言語演習 情報ネットワーク特論.
配列変数とポインタ 静的確保と動的確保 ポインタ配列 2次元配列 時間計測 第1回レポートの課題
システムプログラミング 第7回、8回 ファイルシステム関連の システムコール
B演習(言語処理系演習)第2回 田浦.
システムプログラミング 第6回 システムコールのエラーメッセージ ファイルシステム 情報工学科 篠埜 功.
システムプログラミング 第12回 プロセス間通信 情報工学科 篠埜 功.
ネットワーク・プログラミング デバイスドライバと環境変数.
システムプログラミング 第10回 プロセス間通信3 簡易Web server(準備) Chat プログラム 担当:青木義満、篠埜 功
岡村耕二 TCP通信プログラム 岡村耕二 情報ネットワーク.
システムプログラミング 第9回 、10回 ハードリンク、シンボリックリンク プロセスの生成
ネットワーク・プログラミング TCPサーバ.
ネットワーク・プログラミング 1対多のプロセス間通信.
ネットワーク・プログラミング パイプライン通信とシグナル.
岡村耕二 UDP通信プログラム 課題と回答例 岡村耕二 情報ネットワーク.
システムプログラミング 第11回 シグナル 情報工学科  篠埜 功.
ネットワーク・プログラミング マルチタスク.
ネットワーク・プログラミング プロセスとファイルシステム管理.
プログラミング入門2 第5回 配列 変数宣言、初期化について
ポートスキャン実習 2002年9月19日 修士1年 兼子 譲 牧之内研究室「インターネット実習」Webページ
モバイルプログラミング第3回 Cプログラミングの基礎( 2 )
岡村耕二 TCP通信プログラム 岡村耕二 情報ネットワーク.
Presentation transcript:

システムプログラミング 第12回 プロセス間通信 情報工学科 篠埜 功

今回の内容 プロセス間通信 シグナル(前回) パイプ(今回) ソケット(今回以降)

プロセス間通信 (IPC:Inter Process Communication) プロセス間でデータのやり取りを行う機構 例) X window system: XサーバとXクライアント World wide web: webサーバーとwebブラウザ

UNIXでのプロセス間通信の機構 パイプ: 1つのUNIXシステム内のプロセス間の通信に用いる パイプやソケットはファイル記述子でアクセス read(), write()システムコールでファイル同様に扱える (上記の他、共有メモリを使ってプロセス間の通信を行う方法もある)

パイプとは? メモリ内に設けられるバッファリング領域 2つのプロセス(親子関係、直系)をパイプで繋ぐ 読み出し用の口と書き込み用の口がある ファイル記述子を使ってアクセス ファイル記述子を共有できる親子関係,直系の間柄のプロセス間通信に用いる シェルのパイプの実装に用いられている

パイプにおけるファイル記述子の共有

単方向パイプ

双方向パイプ

パイプの作成 fd[0] : 読み出しモードでオープンされたファイル記述子 fd[1] : 書き込みモードでオープンされたファイル記述子 #include <unistd.h> int pipe ( int fd [2] ); int fd [2] : ファイル記述子 ※正常終了すると値0を返し, エラーの場合には-1を返して外部変数errnoにエラーを示す値をセット 引数fdで渡された配列の各要素に、作成したパイプのファイル記述子を格納して返す。 fd[0] : 読み出しモードでオープンされたファイル記述子 fd[1] : 書き込みモードでオープンされたファイル記述子

単方向パイプとファイル記述子

単方向パイプによるプロセス間通信 (例)新たなプロセスを生成し,子プロセスから親プロセスにコマンド行から入力したメッセージを送る

例(打ち込んで確認) #include <stdio.h> #include <unistd.h> #define BUFSIZE 256 int main (int argc, char *argv[]) { char buf[BUFSIZE]; int fd[2]; int pid; int msglen; if(argc != 2) { fprintf(stderr, "Usage: %s message\n", argv[0]); exit(1); } if(pipe(fd) == -1) { /* パイプのオープン */ perror("pipe");

/* 続き */ if((pid = fork()) == 0) { close(fd[0]); /* fd[0]は使わないので閉じる */ msglen = strlen(argv[1]) + 1; if(write(fd[1], argv[1], msglen) == -1){ perror("write"); exit(1); } close(fd[1]); /* 使い終わったので閉じる*/ else if(pid >= 1) { close(fd[1]); /* fd[1]は使わないので閉じる */ if(read(fd[0], buf, BUFSIZE) == -1){ perror("read"); printf("Message from child process : %s\n", buf); close(fd[0]); /* 使い終わったので閉じる*/ wait(NULL); /* 子プロセスの終了を待つ */ /* 続き */ else { perror("fork"); exit(1); } exit(0);

演習課題 単方向パイプでint型のデータ1つ(20など)を子プロセスから親プロセスへ送り,親プロセスで受け取った後にその内容を表示するプログラムを作成せよ。 int型のデータはプログラム内で与えるものとする。   ヒント: &演算子、sizeof演算子を用いる。

単方向パイプによる シェルのパイプ機能の実現 $ ps | less psを実行するとき標準出力をパイプにし、 lessコマンドを実行するとき標準入力をパイプにする プロセス間通信

dupシステムコール int dup (int oldfd) ファイル記述子を複製する。 引数に、複製元のファイル記述子を与える。 正常終了すると複製先のファイル記述子を返し、エラーの場合は-1を返して外部変数 errno にエラーを示す値をセットする。複製先のファイル記述子は、現在使用されていないファイル記述子のうち最小のものが自動的に選ばれる。(典型的な使用例としては、0番か1番をcloseシステムコールで閉じて、空き状態にしてからdupシステムコールを呼び出す。)

例(入力して確認) 入力後、 $ ./a.out ps less などで確認する。 #include <stdio.h> #include <unistd.h> #include <stdlib.h> int main(int argc, char *argv[]) { int fd[2]; int pid; if( argc != 3 ) { fprintf(stderr, "Usage: %s command1 command2\n", argv[0]); exit(1); } if( pipe(fd) == -1 ) { perror("pipe"); 入力後、 $ ./a.out ps less などで確認する。

続き execシステムコールで変身後もファイル記述子はdefaultで引き継がれる。 else if( pid >= 1 ) { close(0); dup(fd[0]); /* 標準入力のパイプへの             切り替え */ close(fd[0]); /* fd[0]はコピー済 */ close(fd[1]); /* fd[1]は使用しない */ if( execl("/bin/sh", "/bin/sh", "-c", argv[2], NULL ) == -1 ){ perror("parent: execl"); exit(1); } else { perror("fork"); exit(0); if( (pid = fork()) == 0 ) { close(1); dup(fd[1]); close(fd[1]); /* fd[1]はコピー済 */ close(fd[0]); /* fd[0]は不要 */ if( execl("/bin/sh", "/bin/sh", "-c", argv[1], NULL ) == -1 ){ perror("child: execl"); exit(1); } execシステムコールで変身後もファイル記述子はdefaultで引き継がれる。

双方向パイプ

双方向パイプによるプロセス間通信 (例)新たなプロセスを生成して,子プロセスと親プロセスとの間でコマンド行から入力したメッセージ(文字列データ)を双方向にやりとり

例(打ち込んで確認) #include <stdio.h> if( pipe(fd1) == -1 ) { #include <unistd.h> #include <stdlib.h> #include <string.h> #include <sys/wait.h> #define BUFSIZE 256 int main(int argc, char *argv[]) { int status, pid, msglen; char buf[BUFSIZE]; int fd1[2], fd2[2]; if(argc != 3) { fprintf(stderr, "Usage: %s message(CtoP) message(PtoC)\n", argv[0]); exit(1); } if( pipe(fd1) == -1 ) { perror("pipe"); exit(1); } if( pipe(fd2) == -1 ) {

if( (pid = fork()) == 0 ) { close(fd1[0]); close(fd2[1]); msglen = strlen(argv[1]) + 1; if( write(fd1[1], argv[1], msglen) == -1 ) { perror("child: write"); exit(1); } if( read(fd2[0], buf, BUFSIZE) == -1 ) { perror("child: read"); printf("message from parent : %s\n", buf); close(fd1[1]); close(fd2[0]);

else if( pid >= 1 ) { close(fd1[1]); close(fd2[0]); if( read(fd1[0], buf, BUFSIZE) == -1 ) { perror("parent: read"); exit(1); } printf("message from child : %s\n", buf); msglen = strlen(argv[2]) + 1; if(write(fd2[1], argv[2], msglen) == -1) { perror("parent: write"); close(fd1[0]); close(fd2[1]); wait(NULL); else { perror("fork"); exit(1); } exit(0);

ソケットを使ったプロセス間通信 パイプ ソケット ファイル記述子を共有できる関係 親と子,親族プロセス間の通信 関連のないプロセス間での相互通信 ネットワーク経由で異なるUNIX上にあるプロセス間の通信 ファイル記述子でアクセス(パイプと同様)

用語説明 ソケット(socket) バインド(bind) ドメイン(domain) ソケットを識別するために公の名前をつける機能 ファイル名や番号で識別 相手ソケットを識別し,無関係の2つのソケットを繋ぐ手段,bind()システムコール ドメイン(domain) ソケットの名前が通用する範囲 UNIXドメインとInternetドメイン

ドメイン UNIXドメイン Internetドメイン 1つのUNIXシステム内のプロセス同士の通信 ソケットの名前: ファイルのパス名 ソケットの名前: ファイルのパス名 ソケット作成→新しいファイルを作成 Internetドメイン ネットワーク上の計算機のプロセス同士の通信 ソケットの名前: IPアドレス + ポート番号(16bit整数) Well-known port : ftp(21), telnet(23)

例(打ち込んで実行) 2つの、親子関係にはないプロセス間で、 メッセージのやりとりを行うプログラム。 サーバープログラムとクライアントプログラムを別々に作成し、実行。 $ gcc –o server unix_server.c $ gcc –o client unix_client.c $ ./server abc & $ ./client def などのように実行する。

サーバプログラム #include <stdio.h> if(argc != 2){ #include <unistd.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/un.h> #define BUFSIZE 256 #define SERVER_SOCKET "mysocket" int main(int argc, char *argv[]) { int sockfd; int ns; struct sockaddr_un server; struct sockaddr_un client; int fromlen; char buf[BUFSIZE]; int msglen; if(argc != 2){ fprintf(stderr, "Usage: %s message(StoC)\n", argv[0] ); exit(1); } if( (sockfd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) { perror("server: socket"); bzero((char *)&server, sizeof(server)); server.sun_family = PF_UNIX; bcopy(SERVER_SOCKET, server.sun_path, sizeof(SERVER_SOCKET)); unlink(SERVER_SOCKET);

(struct sockaddr *)&server, sizeof(server)) == -1) { if( bind(sockfd, (struct sockaddr *)&server, sizeof(server)) == -1) { perror("server: bind"); exit(1); } if( listen(sockfd, 5) == -1) { perror("server: listen"); bzero((char *)&client, sizeof(client)); fromlen = sizeof(client); if( (ns = accept(sockfd, (struct sockaddr *)&client, &fromlen)) == -1 ){ perror("server: accept"); printf("\nconnect request from: %s\n", client.sun_path); if( read(ns, buf, BUFSIZE) == -1 ) { perror("server: read"); exit(1); } printf("\n<SERVER> message from client : %s\n",buf); msglen = strlen(argv[1]) + 1; if( write(ns, argv[1], msglen) == -1 ) { perror("server: write"); close(ns); close(sockfd); exit(0);

クライアントプログラム if(argc != 2){ fprintf(stderr, "Usage: %s message(StoC)\n", argv[0] ); exit(1); } if( (sockfd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) { perror("client: socket"); bzero((char *)&server, sizeof(server)); server.sun_family = PF_UNIX; bcopy(SERVER_SOCKET, server.sun_path, sizeof(SERVER_SOCKET)); #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/un.h> #define BUFSIZE 256 #define SERVER_SOCKET "mysocket" int main(int argc, char *argv[]) { int sockfd; struct sockaddr_un server; char buf[BUFSIZE]; int msglen;

if( connect(sockfd, (struct sockaddr *)&server, sizeof(server)) == -1){ perror("client: connect"); exit(1); } msglen = strlen(argv[1]) + 1; if( write(sockfd, argv[1], msglen) == -1 ) { perror("client: write"); if(read(sockfd, buf,BUFSIZE) == -1 ) { perror("client: read"); } printf("\n<CLIENT> message from server : %s\n\n", buf); close(sockfd); exit(0);