ネットワークプログラミング講座

並行サーバーの作り方
並行サーバーの作り方











fork()を利用した並行サーバの注意点:親プロセスの義務
forkシステムコールの要点①基本構文
forkシステムコールの要点②変数の複製と、新たなメモリ領域の確保
forkシステムコール直後のメモリ領域の状況
execシステムコール後のメモリ領域の状況
単純サーバから、反復型サーバへの改造
反復型サーバから平行サーバへの改造の要点
平行サーバのプログラムコード①要求受付ソケットとシグナルハンドラ
平行サーバプログラムコードの要点① Wait関数と、listenコール
平行サーバのプログラムコード②サーバループ
平行サーバプログラムコードの要点② acceptコールと、終了した子プロセス
の回収
並行サーバーの作り方
fork()を利用した並行サーバの注意点:
親プロセスの義務




子プロセスが終了すると、「どのような終了状態だったか」が親プ
ロセスに伝えられる
 システムが親プロセスに通知
 シグナルを利用
親プロセスは子プロセスの終了状態を見届けなければならない
 親プロセスが子プロセスの終了状態を受け取らなくては,子
プロセスは成仏できずにゾンビプロセスに変わる
子プロセスが死んで,終了状態を受け取らずに親プロセスが死
ぬと,ゾンビプロセスがいつまでも残る
子プロセスが終了する前に親プロセスが死ぬと?
 プロセスID1のinitが養子として引き取ってくれる
並行サーバーの作り方
forkシステムコールの要点
①基本構文
int pid;
if( (pid = fork()) == 0) {
/* child process */
} else if(pid > 0) {
/* parent process */
} else {
perror("fork()");
}
並行サーバーの作り方
forkシステムコールの要点
②変数の複製と、新たなメモリ領域の確保


変数がコピーされる
 int numberの中身を考えてみよう
別のメモリ領域が確保される
original process id: 21146
original parent process id: 20587
this is parent process
number: 25
fork() return value: 21147
parent process id: 21146
parent parent process id: 20587
number: 25
press enter
this is child process
number: 15
fork() return value: 0
child process id: 21147
child parent process id: 21146
number: 15
press enter
並行サーバーの作り方
forkシステムコール直後のメモリ領域の状況
スタック領域
変数領域
プログラム
コード領域
子プロセスは、親プロセス
のプログラムコード領域を
共有、変数領域は複製、
スタックのみが独立
並行サーバーの作り方
execシステムコール後のメモリ領域の状況
スタック領域
変数領域
プログラム
コード領域
子プロセスと親プロセスのメモリ領域・
領域の内容は、完全に独立
並行サーバーの作り方
単純サーバから、反復型サーバへの改造
単純に、一回の接続で、サーバー
は終了。
何度でも、反復して、サーバーに
接続できるようになる。
但し、同時には1つの クライアント
しか受け付けられません。
並行サーバーの作り方
反復型サーバから平行サーバへの
改造の要点

同時に複数のクライアントと応対するためには、プロセスを分岐して
個々のクライアントにひとつのプロセスを対応させる。

listen関数で同時接続の数を1以上にする。
accept関数でクライアントソケットを入手したら ただちにfork関数で
プロセスを分岐する。
クライアントとの通信は子プロセスが担当するので、親プロセスには
クライアントへのソケットは不要なので閉じる。
親プロセスはすぐに accept関数で次のクライアントを待機する。
子プロセスにはbind関数で使った基本ソケットは不要なので閉じる。
クライアントへのソケットだけを使って通信する。
子プロセスはexit関数で終了する。
親プロセスは子プロセスをwait関数で待たなければならないが、
acceptで止まっているので、CHILDシグナルを利用する。






並行サーバーの作り方
平行サーバのプログラムコード
①要求受付ソケットとシグナルハンドラ
並行サーバーの作り方
平行サーバプログラムコードの要点
① Wait関数と、listenコール

Wait関数をSIGCHLDのシグナルが親プロセスに届いたときに
自動的に実行されるシグナルハンドラにする。
 Wait関数をSIGCHLDのシグナルハンドラに登録するため
に signal関数をプログラム冒頭で実行する。
 終了した子プロセスがすべてを回収するようにwaitpid関数
をループで回す。
 シグナルハンドラは 一旦実行されるとその登録が解除さ
れるので、シグナルハンドラ中で自分自身で再登録する。

listenでは必要な回線数を同時接続できるように指示する。
 OSが回線分の情報を扱うテーブルを用意してくれる。
平行サーバのプログラムコード
②サーバループ
並行サーバーの作り方
並行サーバーの作り方
平行サーバプログラムコードの要点
② acceptコールと、終了した子プロセスの回収

acceptでクライアントと接続して、クライアント情報を表示したらすぐ
に forkでプロセスを分岐する。
 子プロセスにクライアントの応対を任せて、 親プロセスは次のク
ライアントを待つ。
 親プロセスには、もはや先のクライアントへのソケットは不要な
のでcloseする。
 逆に子プロセスにとっては親から引き継いだベースソケットは不
要なので closeする。

親は普通waitで子プロセスが終了するのを待つが、先にSIGCHLD
でWait関数登録しておいたので、明示的にwait を行う必要はない。
acceptで待っている間に子プロセスが終了すると、自動的にWait関
数に制御が移る。
親プロセスは、終了した子プロセスを回収して、再び accept に戻る。

