というわけで腰を据えて考えてみました。対象はC言語です。
■諸論
なぜselectシステムコールが分からないのか。
それはネットワークプログラミングがいまいち分かってないから。
なぜネットワークプログラミングが分かっていないのか。
うん。これは考える価値のある問題です。
なぜネットワークプログラミングが分かっていないか。それは通信の手続きに腑に落ちない点があるからです。
というわけで、まずネットワークプログラミングの手続きを振り返ってみます。
■ネットワークプログラミング概論
【サーバー】
いろんなサーバーの形態がありますが、selectについて語りたいので複数のクライアントから接続を受け付けるパターンを考えます。
1.socket() → ソケットを作成します。
2.bind() → ソケットアドレス構造体を初期化して、ソケットとバインドします。
3.FD_ZERO(), FD_SET() → fd_set構造体を初期化してソケットを登録します。
※ fd_set構造体は、複数のソケットを放り込んでおくための入れ物です。selectの監視対象です。
4.listen() → ソケットから読み込む準備をします。
5.loopに入ります
6.selectでfd_setの中身をチェックします。
以降の動作は、selectの第5引数"struct timeval *timeout"に何を設定するかによって変わります。
(1)第5引数にNULL、あるいは0を指定すると、selectはずっと監視し続けます。何らかのイベントが発生するまで、関数が戻らない状態になります。(文書によっては"0を指定するとすぐにselectから復帰する"という記載がありますが、私の環境(cygwin)では入力待ち状態となりました)
(2)0以上の値をセットした*timeoutを渡すと、その期間だけ監視します。設定された時間が経過すると、selectシステムコールが終了し、プログラム上の次のステップに移ります。
(1)と(2)の違いをどう利用すればいいのか、私にはアイデアがありません。簡単なサンプルプログラムを動かすレベルであれば、どちらでも構わないように思えます。複雑なクラサバネットワークアプリを書くと違いが効いてくるのかもしれません。
Webを調べたところ、タイムアウトに依存したプログラムを書いてはならない、という意見もあるようです。移植性が低くなるとのこと。確かに下手にややこしくするより、selectで待つ、と考えた方がプログラムの見通しも良くなる気がします。
7.selectの戻り値を見て処理を振り分けます。
-1 → エラーが発生しています。
0 → 空振りしています。
上記以外 → ファイルディスクリプタが読み込み可能になっています。
8.FD_ISSETを使って読み込み可能なファイルディスクリプタ(以下FD)を調べます。
9.8で調べたFDに対して、読み込み処理を行います。このときforkして子プロセスに入出力を任せたりします。
【クライアント】
1.socket() → ソケットを作成します。
2.connect() → sockaddr_in構造体に接続先情報(IPアドレス、ポート番号など)をセットして接続します。
3.FD_ZERO(), FD_SET() → fd_set構造体を初期化してソケット(サーバー)を登録します。
4.select() → fd_set構造体の中身をチェックします。
5.読み込み可能なFDから読んだり、書いたりします。
■何が分かりづらいか
> なぜネットワークプログラミングが分かっていないか。それは通信の手続きに腑に落ちない点があるからです。
サーバーでの動きは以下のような流れになっていて、
ソケットの作成 → ポートへバインド → listen → select → read/write
まあ、慣れもありますが分からなくもないですね。
腑に落ちないのは、listenで待つのではなく、次のselectで待たなければならない、という点でしょうか。
> なぜselectシステムコールが分からないのか。
ということで、何でselectで待つんだよ。という点が、ネットワークプログラミングで腑に落ちない点であることが、書きながら分かってきました。(こういうのなんて言うのかな。自縄自縛?)
そういうもんだ、と思ってしまえばそれで済むし、それ以上突っ込むと、物理レイヤの実装まで踏み込む必要がありそうです。でもそうするには体力と時間が足りない。
■結論
まあ、ネットワークプログラミングなんてこういうもんだと。習うより慣れろ。以上。
参考)
クライアント・サーバプログラムI(PDF) (お勧め)
C言語講座 TCP/IPプログラム(その2:サーバ)
ソケットの起源
ネットワークプログラミングの基礎知識
.
0 件のコメント:
コメントを投稿