Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

select関数でパケット受信をチェック する時のFD_ZERO,FD_SET関数 の必要性って?

2,025 views
Skip to first unread message

KMochida

unread,
Dec 6, 2004, 12:39:32 PM12/6/04
to
KMochidaと申します。ソケットプログラミングを学習しています。
疑問があります。

サーバ側ではディスクリプタsocにパケットが届いているかをチェックする為に、
int n;
fd_set mask;
FD_ZERO(&mask);
FD_SET(0,&mask);
FD_SET(soc,&mask);
select(soc+1,&mask,NULL,NULL,NULL);
n=FD_ISSET(soc,&mask);

として返値nを吟味する事でsocにパケットが届いているかを知る事が出来るのですよ
ね。
つまり、

$ ulimit -a | grep max
max user processes (-u) 63

の場合、上記のコードは

mask.fds_bits[1]、mask.fds_bit[0]、の64ビット分を「0」にする。
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
0000

0番ディスクリプタとsoc番ディスクリプタを「1」にする。
(下記例はsocの評価値が「4」の場合)
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0001
0001

0番ディスクリプタ~soc番ディスクリプタにパケットが届いているかを調査する。
届いているディスクリプタ(ビット目)だけ「1」にして、届いていないものは全て
「0」に書換える。
(例 4番ディスクリプタのみに届いている場合は
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0001
0000
0番ディスクリプタのみに届いている場合は
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
0001
3番ディスクリプタのみに届いている場合は
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
1000)

実際に4番ディスクテリプタに届いているかの判定は最後にFD_ISSET関数の返値に
よって知りうる事ができる。
nの値が「1」ならsocディスクリプタにパケットが届いている。「0」なら届いていな
い。

という具合の処理になるのですよね?
(勘違いしてましたら、ご指摘ください)

としますと
FD_ZERO(&mask);
FD_SET(0,&mask);
FD_SET(soc,&mask);
は不要なんじゃないでしょうか?

select(soc+1,&mask,NULL,NULL,NULL);
n=FD_ISSET(soc,&mask);

だけで十分なような気がするのですが、勘違いしてましたら、ご指摘ください。

ku...@gssm.otsuka.tsukuba.ac.jp

unread,
Dec 6, 2004, 5:14:11 PM12/6/04
to
久野です。

kaor...@plum.freemail.ne.jpさん:


> select(soc+1,&mask,NULL,NULL,NULL);
> n=FD_ISSET(soc,&mask);
> だけで十分なような気がするのですが、勘違いしてましたら、ご指摘ください。

maskの中でビットが「1」になっているものに対応するチャネルのみ
をselectは監視しますよね。

だから初期化は必要なんじゃないですか? 久野


KMochida

unread,
Dec 7, 2004, 12:41:06 AM12/7/04
to
KMochidaと申します。ご回答有難うございます。

> maskの中でビットが「1」になっているものに対応するチャネルのみ
> をselectは監視しますよね。
>
> だから初期化は必要なんじゃないですか? 久野

えーと、select関数に関する
『届いているディスクリプタ(ビット目)だけ「1」にして、届いていないものは全て
「0」に書換える。』
という解釈が間違っているんですね。
(一応、アチコチの参考書を調べてはみたのですがよく理解できませんで)

久野さまのお話だと
select(soc+1,&mask,NULL,NULL,NULL);は
0番ディスクリプタ~soc番ディスクリプタ
の内でビットが立っているものに関してだけのバケット到着の有無を調査するんです
かね。
すると、
1番ディスクリプタ~(soc-1)番ディスクリプタ
はFD_ZERO、FD_SET関数でビットは立てられていないのでselect関数では
1番ディスクリプタ~(soc-1)番ディスクリプタ
にパケットが届いていようがいまいが
何にもしないという解釈で宜しいんでしょうか。

としますと、前記事において
『3番ディスクリプタのみに届いている場合は


0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000

1000)』
は間違いで
『3番ディスクリプタのみに届いている場合は


0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000

0000』
という風に3番ディスクリプタにビットは立たないという事になるんですね。

ku...@gssm.otsuka.tsukuba.ac.jp

unread,
Dec 7, 2004, 12:55:32 AM12/7/04
to
久野です。

kaor...@plum.freemail.ne.jpさん:
> (一応、アチコチの参考書を調べてはみたのですがよく理解できませ
> んで)

manページを読むべきなんだと思いますが。私もmanページを読んでい
るだけですし。

> の内でビットが立っているものに関してだけのバケット到着の有無を
> 調査するんですかね。

と思いますが。

> はFD_ZERO、FD_SET関数でビットは立てられていないのでselect関数
> では1番ディスクリプタ~(soc-1)番ディスクリプタにパケットが届い
> ていようがいまいが何にもしないという解釈で宜しいんでしょうか。

そうなってないと、調べたくもないディスクリプタまで調べられてし
まって使いにくいじゃないですか。

> 『3番ディスクリプタのみに届いている場合は
> という風に3番ディスクリプタにビットは立たないという事になるんですね。

え、最初に1だったもののうち、実際にデータが到着したものは1のま
ま残り、到着しなかったものは0になるんじゃないの。

だから届いてるなら1は立つと思うけど。 久野

SAITOH Akinori

unread,
Dec 7, 2004, 4:45:57 AM12/7/04
to
鳥取環境大学の齊藤です

ku...@gssm.otsuka.tsukuba.ac.jp wrote:
> manページを読むべきなんだと思いますが。私もmanページを読んでい
> るだけですし。

ですね。manページが第1に調べるべきものでしょう。

select(2)にかんしては、linux/FreeBSD/NetBSD見比べてみましたが、
特に大きな差異はないようだし(linuxのmanページは時としてBSDより
かなり簡略されてて居ることがあるのですが、selectに関しては
linuxのほうが分かりやすいかもしれません。BSDのほうは「ディスクリプタのア
ドレス」という表現が出てきて分かりにくい)。

ただ、頭から字を追って読んでもわけが分からないかも。

selectは複数のファイルディスクリプタを並行に見張るシステム
コールであるということを頭において読むと、理解できると思います。

P.S.
「WEBにある解説記事よりmanページのほうがコンパクトで正確で
わかりやすい」と思えるようになったら、もう初心者の気持ちが
分からなくなっている証拠だったりして。


--
齊藤明紀 saitoh at kankyo-u ac jp

OOTANI TAKASHI

unread,
Dec 7, 2004, 1:08:48 PM12/7/04
to
本筋のほうは、久野さんがフォローしているので。

In article <cp25gl$alc$1...@caraway.media.kyoto-u.ac.jp>


"KMochida" <kaor...@plum.freemail.ne.jp> writes:
> $ ulimit -a | grep max
> max user processes (-u) 63
>
> の場合、上記のコードは
>
> mask.fds_bits[1]、mask.fds_bit[0]、の64ビット分を「0」にする。

fd_set のビット数とmax user processesは関係ないので、ビット数を知りたければ
システムヘッダファイルで、FD_SETSIZE の定義を探すのが良いかと思います。
printf("%d\n",sizeof(fd_set)*8); でもいいですけど。
--
tksotn

KMochida

unread,
Dec 9, 2004, 2:27:47 AM12/9/04
to
KMochidaです。皆様、ご回答大変感謝致します。m(_ _)m


> そうなってないと、調べたくもないディスクリプタまで調べられてし
> まって使いにくいじゃないですか。
>> 『3番ディスクリプタのみに届いている場合は
>> という風に3番ディスクリプタにビットは立たないという事になるんですね。
> え、最初に1だったもののうち、実際にデータが到着したものは1のま
> ま残り、到着しなかったものは0になるんじゃないの。
> だから届いてるなら1は立つと思うけど。 久野

分かってきました。

とりあえず、実験的してみました。
各関数処理後のビットがどうなっているか逐一吐かせてみました。

FD_ZERO(&mask);


mask.fds_bits[1]、mask.fds_bit[0]、の64ビット分を「0」にする。

0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
0000

FD_SET(0,&mask);

mask.fds_bits[1]、mask.fds_bit[0]、の0ビット目を「1」にする。


0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000

0001

FD_SET(4,&mask);


mask.fds_bits[1]、mask.fds_bit[0]、の4ビット目を「1」にする。
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0001
0001

FD_SET(9,&mask);
(select関数での有効ビット幅外ではどうなるか観察する為に更に9ビット目を立てて
みる)

mask.fds_bits[1]、mask.fds_bit[0]、の9ビット目を「1」にする。
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0010 0001
0001

select(4+1,&mask,NULL,NULL,NULL);

selectの返値は1であった
(0~4番ディスクリプタの内、少なくともひとディスクリプタにバケットが到達した
と分かる)。

mask.fds_bits[1]、mask.fds_bit[0]


0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0001
0000

となりました
(有効ビット幅外である9番ディスクリプタも「0」にされちゃいました)。

、、、という事は
select(n+1,&mask,NULL,NULL,NULL);は
0番~n番ディスクリプタでパケットが到達しているディスクリプタでしかも、予め
ビットが立っているディスクリプタを「1」にする(勿論、複数のディスクリプタがこ
の用件を満たしてれば複数のディスクリプタが1となる)。
そして、それ以外のディスクリプタ、つまり、
最初から「0」になっているディスクリプタ、パケットが到達していないディスクリ
プタ、有効ビット幅外のディスクリプタは全て「0」にしてしまう
のですね。

> かなり簡略されてて居ることがあるのですが、selectに関しては
> linuxのほうが分かりやすいかもしれません。BSDのほうは「ディスクリプタのア
> ドレス」という表現が出てきて分かりにくい)。
> ただ、頭から字を追って読んでもわけが分からないかも。
> selectは複数のファイルディスクリプタを並行に見張るシステム
> コールであるということを頭において読むと、理解できると思います。
> P.S.
> 「WEBにある解説記事よりmanページのほうがコンパクトで正確で
> わかりやすい」と思えるようになったら、もう初心者の気持ちが
> 分からなくなっている証拠だったりして。

有難うございます。
manの方は読んでて混乱してきて、ついイラストも載っている書籍やWEBの解説を読ん
でしまいます。
manで読めるようになりたいと思います。

> fd_set のビット数とmax user processesは関係ないので、ビット数を知りたけれ



> システムヘッダファイルで、FD_SETSIZE の定義を探すのが良いかと思います。
> printf("%d\n",sizeof(fd_set)*8); でもいいですけど。

cygwinでは


$ ulimit -a | grep max
max user processes (-u) 63


printf("%d\n",sizeof(fd_set)*8);
を試すと「64」になりましたのですっかり勘違いしておりました。

因みに、RedHat9上では
$ uname -a
Linux hoge.foo.dydnd.net 2.4.20-8 #1 Thu Mar 13 17:54:28 EST 2003 i686 i686
i386 GNU/Linux
$ ulimit -a
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
file size (blocks, -f) unlimited
max locked memory (kbytes, -l) unlimited
max memory size (kbytes, -m) unlimited
open files (-n) 1024
pipe size (512 bytes, -p) 8
stack size (kbytes, -s) 8192
cpu time (seconds, -t) unlimited
max user processes (-u) 7168
virtual memory (kbytes, -v) unlimited

となっていて、

printf("%d\n",sizeof(fd_set)*8);
を試すと「1024」となりました。でもfd_set のビット数はopen files数とも違うん
ですね。
飽くまで、FD_SETSIZEで定義されている値なのですね。

0 new messages