180 likes | 332 Views
Talk プログラムのヒント 1. CS-B3 ネットワークプログラミング &情報科学科実験 I. このスライドについて. このスライドでは皆さんがプログラムを書いたり,関数を調べたりする過程で行き詰ると予想される部分について簡単に解説します.. このスライドの目的は自主学習のサポートであり,説明が簡略化されています.完全な理解には自主学習が必要なので注意してください.. 目次. よくつまずくところ 解決方法の例 select() とは ファイルディスクリプタとは ファイルディスクリプタ 具体的な仕様 ファイルディスクリプタ 使用例 select() の引数
E N D
Talkプログラムのヒント 1 CS-B3 ネットワークプログラミング &情報科学科実験I
このスライドについて このスライドでは皆さんがプログラムを書いたり,関数を調べたりする過程で行き詰ると予想される部分について簡単に解説します. このスライドの目的は自主学習のサポートであり,説明が簡略化されています.完全な理解には自主学習が必要なので注意してください.
目次 • よくつまずくところ • 解決方法の例 • select()とは • ファイルディスクリプタとは • ファイルディスクリプタ 具体的な仕様 • ファイルディスクリプタ 使用例 • select()の引数 • select()の動作 • まとめ
よくつまずくところ キー入力しなければ 次に進めない 送っている最中は キー入力,受信ができない 受信待ちの間は キー入力,送信ができない こんなプログラムのままになっていませんか? while(1) { fgets()でキー入力を取得; send()で入力文字を送信; recv()で相手からメッセージを受け取る; }
解決方法の例 こんなプログラムが書けるとよいですね. while(1) { if (fgets()すべきならば) { fgets()でキー入力を取得; } if (send()すべきならば) { send()で入力文字を送信; } if (recv()すべきならば) { recv()で相手からメッセージを受け取る; } }
解決方法の例 少しだけ具体的に書くと… while(1) { select()の引数の設定; select(引数); if (FD_ISSET(標準入出力,ファイルディスクリプタの集合)) { fgets()でキー入力を取得; } if (FD_ISSET(send用ソケット,ファイルディスクリプタの集合)) { send()で入力文字を送信; } if (FD_ISSET(recv用ソケット,ファイルディスクリプタの集合)) { recv()で相手からメッセージを受け取る; } }
select()とは • ソケット,標準入出力,ファイルが読み込み可能か,書き込み可能かを調べるときに使う. • どれかが読み込み可能,書き込み可能,またはタイムアウトになるまではselect()は待機状態になる. あらかじめ 監視する目的 (読み込み,書き込み) 監視する対象(ソケットか,標準入力か…) Select()のタイムアウト を決めなければならない ファイルディスクリプタの知識が必要
ファイルディスクリプタとは select()が監視するもの = ファイルディスクリプタの集合の変化 • ファイルディスクリプタ • ソケット,標準入出力,ファイルを識別する値 socketID = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); これ • 標準入出力のファイルディスクリプタ • stdin:0, stdout:1, stderr:2 • ファイルディスクリプタの集合 • 複数のファイルディスクリプタの値をまとめて管理するもの
ファイルディスクリプタ具体的な仕様 fd_set型変数 ファイルディスクリプタの集合 fd_set set; • select()実行前 • ソケットや標準入出力に対応するファイルディスクリプタがfd_set型変数に登録されていれば,状態変化の監視対象となる. • select()実行後 • ソケットや標準入出力に対応するファイルディスクリプタがfd_set型変数に登録されていれば,読み取り可能状態である.
ファイルディスクリプタ具体的な仕様 ファイルディスクリプタの集合の操作用マクロ • FD_ZERO(fd_set *set); 集合をリセットする • FD_SET(int fd, fd_set *set); fdを集合に登録する • FD_SET(STDIN_FILENO, fd_set *set);標準入力を集合に登録する • FD_ISSET(int fd, fd_set *set); fdが集合に登録されているか確認 • FD_CLR(int fd, fd_set *set); fdを集合から取り除く
ファイルディスクリプタ登録例 ※ソケットをsoketIDとする. fd_setsocketSet; ファイルディスクリプタの集合を作成 FD_ZERO(&socketSet); ファイルディスクリプタ集合の初期化 FD_SET(socketID, &socketSet); ソケットを集合に登録する FD_SET(STDIN_FILENO, &socketSet); stdinを集合に登録する 変数socketSetをselect()に渡せばソケットやstdinから文字列を受け取れるか確認できる.
select()の引数 select(ファイルディスクリプタの最大値 + 1, ファイルディスクリプタの集合(読み込み可能かどうかを調べる), ファイルディスクリプタの集合(書き込み可能かどうかを調べる), ファイルディスクリプタの集合(例外が発生したかどうかを調べる), タイムアウト); • ファイルディスクリプタの集合 • ファイルディスクリプタは3種類指定できる. • それぞれ,読み込み可能かどうか,書き込み可能かどうか,例外が発生したかどうかを監視するためにある. • 読み込み可能かどうかを調べるためにselect()が用いられることが多い.
select()の引数 select(ファイルディスクリプタの最大値 + 1, ファイルディスクリプタの集合(読み込み可能かどうかを調べる), ファイルディスクリプタの集合(書き込み可能かどうかを調べる), ファイルディスクリプタの集合(例外が発生したかどうかを調べる), タイムアウト); • ファイルディスクリプタの最大値 + 1 • 3種類のファイルディスクリプタの集合のうち,最も値の大きいファイルディスクリプタの値 • 例) socket1 と socket2の監視をしたい場合 • socket1 > socket2 ならば socket1 + 1 • socket1 < socket2 ならば socket2 + 1 • タイムアウト • この時間を過ぎるとselect()の待機状態は終了する. • (※詳細はstructtimevalについて調べてください)
select()の動作 ファイルディスクリプタの集合に登録されたソケットや標準入力に変化があるまで待機する. ソケットや標準入力に変化があった場合は,ファイルディスクリプタの集合をそれらのみが登録された状態に変更する.select()の待機状態は終了する. FD_ISSETを用いれば,どこから文字列を受け取ればよいかわかる
Select関数を用いた並列処理の流れ fd_setsocketSet FD_ZEROでsocketSetの初期化 socketID stdin FD_SETでsocketSetへの登録 select(socketID+1,&socketSet,NULL,NULL,&tv) 集合内のどれかが読み込み可能となるまで待機 socketID stdin socketIDからの読み取りが可能となった ⇒select関数は集合からsocketID以外を削除する FD_ISSETでどのファイルディスクリプタが 集合内に残っているかを判別⇒各種処理 socketID
select()の動作 最初に見たプログラムの意味が分かってきた気がしませんか? while(1) { select()の引数の設定; select(引数); if (FD_ISSET(標準入出力,ファイルディスクリプタの集合)) { fgets()でキー入力を取得; } if (FD_ISSET(send用ソケット,ファイルディスクリプタの集合)) { send()で入力文字を送信; } if (FD_ISSET(recv用ソケット,ファイルディスクリプタの集合)) { recv()で相手からメッセージを受け取る; } }
select()の動作 • 注意(重要) • ファイルディスクリプタの集合の設定はselect()を実行するたびに行ってください • select()によってファイルディスクリプタの集合は変更されます. • タイムアウトの設定もselect()を実行するたびに行ってください • タイムアウトを記録した変数もselect()実行後に変更される可能性があります. つまり while(1) の無限ループ内で,select()実行前に毎回 ファイルディスクリプタ集合とタイムアウトの設定を行う必要がある
まとめ • select()を使うとfgets(),send(),recv()を行うべきタイミングが分かる • select()は標準入力やソケットをファイルディスクリプタの集合をもとに監視する このスライドのヒントはあくまでも実装方法の一例です. ほかにも実装方法があるかもしれません. 以上の内容をヒントにして,自主学習やプログラムの実装を進めてみてください.