Apache過去にPHPで以下のコードを実行した場合、このprintの結果はどこに吐かれるんだろう、と混乱したことがあった。World");CLIで実行すれば、制御端末のコンソールに表示されるんだろうけど、NginxやApacheのようにWebサーバー越しで実行している場合、あれーとわからなくなったのだ。実際のところ記憶が曖昧だけど、HTMLとして出力されていたり、どっかのログに吐かれていたような気がする。この疑問を解消しようと思ったとき、そもそもC言語で実装されているNginxやApacheでどうやってPHPを動かしているんだろうという部分に行き当たることになった。年末からLinuxでWebサーバーをお試しでつくってみようということをやっていたので、実装の参考にするべくApacheのソースコードを眺めつつ、まずはApacheから任意のプログラムを実行するCGIの仕組みについて調べることにした。Linuxの基本調べるにあたっては、以下の書籍を参考にしています。自プロセスを新しいプログラムで上書きして実行するAPIであるexecを使う。以下はApacheの該当部分のソースコード。execで実行されるので、毎回プロセスを生成する必要があり、その分のオーバーヘッドが大きい。C言語からNode.jsを実行するあれ?PHPは?と思ったけど、ひとまずC言語以外ならなんでもいいかと思い、気づいたらNode.jsをインストールしていた。いうことでC言語からNode.jsを実行してみる。実行するjsは以下のように文字列を標準出力に吐くだけのプログラム。sample.jsconsole.log("hello");これをC言語から呼ぶには、exec族と呼ばれる関数を使う。exec族にはいろんな種類があるんだけど、ここではexecveを使うことにする。execveは引数で指定したプログラムを自プロセスに上書きしてくれるLinuxのシステムコールで、他のexec族の関数はexecveをラップしているライブラリ関数とのこと。以下のように使うことができる。`execve`の第1引数には、実行するプログラムのパスを書いて、第2引数にはプログラムに渡す引数を文字列の配列として渡す。文字列の配列の最初の要素はプログラムの名前をセットする慣習があるので、`node`という文字列をセットした。第3引数は、プログラムを実行する際の環境変数を設定する。場合、現在の環境変数をそのまま使う。exit(1);}前述の通り、execveは引数で指定したプログラムを自プロセスに上書きするので、execve以降の処理は実行されることがない。これを実行すると、以下のようにsample.jsの実行結果が標準出力に表示された。./exechelloforkと組み合わせるこれで目的の8割ぐらいは達成できたんだけれども、WebサーバーのCGIとして使う場合、Node.jsで処理した結果をHTTPのレスポンスとして返す必要がでてくる。今のままだと、Node.jsの処理の実行が終わるとそのままプログラムが終了してしまうため、これに対応するためにforkを使うことにする。forkは自身のプロセスをコピーして新しいプロセスをつくるLinuxのシステムコール。execveは任意のプログラムをプロセスに上書きするので、forkしてそれ用にプロセス一個つくっとこうという感じでしょうかね。www.tohuandkonsome.siteforkと組み合わせると以下の通りになります。exit(0);}子プロセスの結果を親プロセスで受け取る最後に子プロセスで実行したNode.jsの結果を親プロセスで取得する。ここでいうNode.jsの結果とは、console.log()で標準出力に出力している文字列helloを指している。Node.jsで使う標準出力の出力先を任意のファイルに変更してみることにする。これはdup関数を使用することで実現できる。exit(0);}この状態で実行すると、sample.txtには文字列helloが書き込まれることが確認できた。これによって、子プロセスでファイルに書き込んだ文字列を親プロセスでオープンしで読むことができそうな気がする。いえ、ファイルのオープン・クローズだったりはオーバーヘッドが高いと聞くので普通はこんなやり方をせずに、プロセス同士でやり取りできるパイプを使う。パイプパイプを使うと、ファイルを用意することなく、プロセス間でデータのやりとりが行える。pipeは、自分のプロセスへの読み取りと書き込み用のファイルディスクリプタを返してくれる。pipeで作成したファイルディスクリプタはforkした場合、そのまま子プロセスに複製される。これにより、子プロセスで書き込み用ファイルディスクリプタに書いて、親プロセスで読み取り用のファイルディスクリプタを読むことでやりとりが可能。子プロセスではread用のファイルディスクリプタは使わないのでクローズする。標準出力は使わないのでクローズ。親プロセスは、write用のファイルディスクリプタは使わないのでクローズする。0;}実際のApacheのコードを読んでも、dupを使ってることが確認できた。FastCGIFastCGIは既存のCGIがリクエストの度にプロセスを生成するオーバーヘッドを解消するための規格。プロトコルの詳細はこのへんに書いてある。https://fastcgi-archives.github.io/FastCGI_A_High-Performance_Web_Server_Interface_FastCGI.htmlApacheでFastCGIをやる場合、mod_fcgidとmod_fastcgiがある。前者はApacheが提供していて、後者はFastCGIの規格を作った?会社が提供している。後者は公式でメンテされることがないので、もし使うのであれば前者がよいかも。mod_fcgidを使ってみたところ、以下の3つのプロセスが起動することが確認できる。大事なのは、FastCGIの規格は、CGI処理用デーモンだけじゃなくって、CGI本体にも適用させる必要がある。C言語でサンプルのFastCGIをつくるのであれば、以下のtiny-fcgi.cが参考になる。実装を見ると、CGI側でLoopしてリクエストを待ち続けていることがわかる。Perl・Cとかのライブラリは提供されているけど、仮にNode.jsでFastCGIをやりたいとなると、自分でFastCGIの規格を読んで実装する必要がある。※それっぽいパッケージはいくつかありそうだった。FastCGIでNode.jsみたいな構成でやる意味はない。17:25ApacheでCGIを実行する仕組みをのぞいてみる関連記事2019-01-022018年の振り返りあけましておめでとうございます。つまみぐいをするような学習方法は螺旋階段のよ...2018-09-153連休だしDocker環境でNuxt.jsをさわってみよう久々の更新。最近、Nuxt.jsとFirebaseで遊んでます。»プロフィール30歳からWebやらなんやらを学び始めた人のブログです。(4)検索はてなブログをはじめよう!konoemarioさんは、はてなブログを使っています。ブログを報告するスターをつけました引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。