たらこ鱈の子、この子どこの子

構造体が分からなくてネットワークプログラムには進んでなかったんだけど、もういいや~とネットワークプログラムをやりだしてみたら、なるほど!という感じになったので、ささっとネットワークプログラムをやってしまってても良かったかもしれない。

かぼちゃさんが以前おっしゃっていた構造体のキャストもガンガン出てきてるのだが、もしかしたらその辺のことを知ってたので頭が理解しやすい状態になっていたのかもしれない。サンクス。

 

サーバークライアント間のやり取りをするときに、例題だとだいたい1対1ですが、インターネットでは1対多数というのは当たり前なのです。どうやっているかという事を超ざっくりと説明すると、サーバー側では子プロセスを生成して、クライアントとの処理を子プロセスにやってもらう。っていう感じで、Apacheを触った事がある人ならそれは割と知っている事だけど、プログラム側から入ってきたらなるほど!と、なお理解しやすい。

ただApacheを例にすると、Apacheの子プロセス生成にはPreforkとかWorkerとかあっ(ry

という事なのです。

長くなるので、その辺はカットだ。
fork()を初めて使って見たので、サンプルプログラムを作ってみたんだけど、おかしな結果になった。

そーす

  1 #include <stdio.h>
  2 #include <sys/types.h>
  3 #include <unistd.h>
  4 #include <sys/wait.h>
  5
  6 int main(void)
  7 {
  8     pid_t result_pid;
  9
 10     if(fork() == 0){
 11         printf("Hello World child\nプロセスは%d、親プロセスは%d\n", getpid(), getppid());
 12     }else{
 13         printf("Hello World parent\nプロセスは%d、親プロセスは%d\n", getpid(), getppid());
 14     }
 15
 16     return 0;
 17 }

実行結果

# ./a.out
Hello World parent
プロセスは3088、親プロセスは2365
[root@localhost program]# Hello World child
プロセスは3089、親プロセスは1

なんでや!見た通りで、子プロセスの親プロセスが1になる。

プロンプトも帰ってるし子プロセスの反抗期なのかしら。
いや、そういう問題ではないが、とにかくおかしい。

補足だけど、2365はシェルのプロセス。

# ps u | grep 2365
root      2365  0.0  0.1 108300  1988 pts/0    Ss   05:33   0:00 -bash

 

自力では解決できなさそうなんで、ググっとググってみたところ、親プロセスが先になくなってしまっているらしい。プロンプトが帰ってきているのもそれが関係している。

なるほどな。参考サイトのプログラムをちょと借りて修正してみた。

そーす

# cat hello.c
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>

int main(void)
{
        pid_t result_pid;

        if(fork() == 0){
                printf("Hello World child\nプロセスは%d、親プロセスは%d\n", getpid(), getppid());
        }else{
                printf("Hello World parent\nプロセスは%d、親プロセスは%d\n", getpid(), getppid());

                int status;

                /* waitpid プロセスの状態変化を待つ関数
                        WUNTRACED 子プロセスが停止した場合にも復帰する*/
                waitpid(result_pid,&status,WUNTRACED);

                /* WIFEXITED(status)
                        子プロセスが正常に終了した場合に真を返す。 */
                if(WIFEXITED(status)){
                        fprintf(stdout,"終了ステータスは %d\n",WEXITSTATUS(status));
        }else{
                        fprintf(stdout,"エラー\n");
        }
    }

        return 0;
}

実行結果

# ./a.out
Hello World parent
プロセスは3100、親プロセスは2365
Hello World child
プロセスは3101、親プロセスは3100
終了ステータスは 0

おお、うまくうごいてくれた。

参考サイトではfork()だけの時もちゃんと動いていて、sleep()したときにこの現象が起きていたようだけど、こちらの環境ではfork()だけでも、親プロセスが先になくなってしまうということになっていたようだ。

という事は逆に利用すればinitで動くプログラムを作れるのかね。

うーん。まだ理解が足りてないなあ。

 

参考サイト

ファイアープロジェクト
forkとwaitとゾンビプロセス

JM Projent
Man page of WAIT

 

Related Posts


投稿者: Takeken

インターネット利用者のITリテラシーを向上したいという設定の2次元キャラです。 サーバー弄りからプログラミングまで手を付けた自称エッセイストなたけけんの物語。

「たらこ鱈の子、この子どこの子」への2件のフィードバック

  1. forkは万能に見えて意外と遣いにくい印象….
    Apache(*1:より言うとTCP/IPスイートのアプリケーションレイヤ以上の手続き)のように,サーバとクライアントの1:1対話が並行されるのであれば有用ですが,例えばチャットプログラムのようにサーバが複数のクライアントを中継するような形になると非常に扱いにくくなります.
    その場合は,スレッドによる並列処理が適していますが,Cでスレッドを書くのは面倒かも?(未経験
    (C++ならboostやcommon c++など主義主張は異なるものの便利なライブラリがある)

    *1
    ご存知かと思いますが,fork()されないサーバプログラムでかつクライアントと対話するアプリケーションプロトコルを持つ場合,一般にDoS攻撃を受けます.
    https://www.ipa.go.jp/security/awareness/vendor/programmingv1/b07_04.html

    1. あ~、チャットみたいな形式はぜんぜん考えてなかったっす・・あくまでイメージですけどforkだと大変そうですね。。。ググってもC++やC#ばかりだ。
      ひとまず今はPrefork型の簡単な監視プログラムを作成してます。
      ソケットをやってると関数&構造体が山ほどでてきて、誰かがプログラムを覚えるのは言葉(単語と文法)を覚えるのと似ているって言ってたのを、まさにそうだなあと感じてるとこです。

      スレッドによる並列処理っていうと、最近の仮想サーバの仮想マルチコアの環境での動作ってどうなるんだろうってぽっと浮かんだけど、色々考え出すとやばいですね(笑)

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です