Talkプログラムのヒント

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_SET(STDIN_FILENO, fd_set *set);
•FD_ISSET(int fd, fd_set *set);
•FD_CLR(int fd, fd_set *set);
集合をリセットする
fdを集合に登録する
標準入力を集合に登録する
fdが集合に登録されているか確認
fdを集合から取り除く
ファイルディスクリプタ
登録例
※ソケットをsoketIDとする.
fd_set socketSet;
ファイルディスクリプタの集合を作成
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()の待機状態は終了する.
(※詳細はstruct timevalについて調べてください)
select()の動作
1. ファイルディスクリプタの集合に登録されたソケットや
標準入力に変化があるまで待機する.
2. ソケットや標準入力に変化があった場合は,ファイル
ディスクリプタの集合をそれらのみが登録された状態に
変更する.select()の待機状態は終了する.
FD_ISSETを用いれば,どこから文字列を受け
取ればよいかわかる
Select関数を用いた並列処理の流れ
fd_set socketSet
FD_ZEROでsocketSetの初期化
socketID
stdin
socketID
stdin
FD_SETでsocketSetへの登録
select(socketID+1,&socketSet,NULL,NULL,&tv)
集合内のどれかが読み込み可能となるまで待機
socketIDからの読み取りが可能となった
⇒select関数は集合からsocketID以外を削除する
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()は標準入力やソケットをファイルディスクリプタの集合を
もとに監視する
このスライドのヒントはあくまでも実装方法の一例です.
ほかにも実装方法があるかもしれません.
以上の内容をヒントにして,自主学習やプログラムの実装を進めてみ
てください.