Talk プログラムのヒント 1
-
Upload
alexis-long -
Category
Documents
-
view
19 -
download
2
description
Transcript of Talk プログラムのヒント 1
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() は待機状態になる.
あらかじめ1. 監視する目的 ( 読み込み,書き込み )2. 監視する対象 ( ソケットか,標準入力か
… )3. 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 を集合から取り除く
ファイルディスクリプタの集合の操作用マクロ
ファイルディスクリプタ登録例
fd_set socketSet; ファイルディスクリプタの集合を作成
FD_ZERO(&socketSet); ファイルディスクリプタ集合の初期化
FD_SET(socketID, &socketSet); ソケットを集合に登録する
FD_SET(STDIN_FILENO, &socketSet); stdinを集合に登録する
変数 socketSet を select() に渡せばソケットやstdin から文字列を受け取れるか確認できる.
※ソケットを soketIDとする.
select() の引数select( ファイルディスクリプタの最大値 + 1, ファイルディスクリプタの集合 ( 読み込み可能かどうかを調べる ), ファイルディスクリプタの集合 ( 書き込み可能かどうかを調べる ), ファイルディスクリプタの集合 ( 例外が発生したかどうかを調べる ), タイムアウト );
•ファイルディスクリプタの集合ファイルディスクリプタは 3 種類指定できる.それぞれ,読み込み可能かどうか,書き込み可能かどうか,例外が発生したかどうかを監視するためにある.
読み込み可能かどうかを調べるために select() が用いられることが多い.
select() の引数select( ファイルディスクリプタの最大値 + 1, ファイルディスクリプタの集合 ( 読み込み可能かどうかを調べる ), ファイルディスクリプタの集合 ( 書き込み可能かどうかを調べる ), ファイルディスクリプタの集合 ( 例外が発生したかどうかを調べる ), タイムアウト );
•タイムアウトこの時間を過ぎると select() の待機状態は終了する.(※ 詳細は struct timeval について調べてください )
•ファイルディスクリプタの最大値 + 13 種類のファイルディスクリプタの集合のうち,最も値の大きいファイルディスクリプタの値
例 ) socket1 と socket2 の監視をしたい場合 socket1 > socket2 ならば socket1 + 1 socket1 < socket2 ならば socket2 + 1
select() の動作1. ファイルディスクリプタの集合に登録されたソケットや
標準入力に変化があるまで待機する.
2. ソケットや標準入力に変化があった場合は,ファイルディスクリプタの集合をそれらのみが登録された状態に変更する. select() の待機状態は終了する.
FD_ISSET を用いれば,どこから文字列を受け取ればよいかわかる
Select 関数を用いた並列処理の流れ
select(socketID+1,&socketSet,NULL,NULL,&tv)集合内のどれかが読み込み可能となるまで待機
FD_ZERO で socketSet の初期化
FD_SET で socketSet への登録
socketIDstdin
fd_set socketSet
socketIDstdin
socketID
socketID からの読み取りが可能となった⇒select 関数は集合から socketID 以外を削除するFD_ISSET でどのファイルディスクリプタが集合内に残っているかを判別⇒各種処理
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() は標準入力やソケットをファイルディスクリプタの集合をもとに監視する
以上の内容をヒントにして,自主学習やプログラムの実装を進めてみてください.
このスライドのヒントはあくまでも実装方法の一例です.ほかにも実装方法があるかもしれません.