この記事で実装されているサーバーは、原理を説明して理解するためにのみ使用されており、シンプルで理解しやすいように努めています。興味のある友人は、引き続き徹底的な変革を行うことができます
Web サーバーを実装したい場合は、Web サーバーの動作原理を一般的に理解する必要があります。 Web サーバーの 1.html を例として、静的テキスト サーバーから始めましょう。
1. サーバーがリッスンするポート番号が 9002 の場合、クライアントはサーバーに http リクエストを送信します。マシン自体では http://localhost:9002/1.html です。
2. サーバーはポート 9002 をリッスンします。リクエストを受信すると、Web ディレクトリ内のリクエストでアクセスする必要がある URI リソースの場所を http ヘッド ヘッダーから取得できます。
3. サーバーは、アクセスする必要があるリソース ファイルを読み取り、それを http エンティティに埋めてクライアントに返します。
概略図は次のとおりです:
php<?phpclass web_config { // 监听的端口号 const PORT = 9003; // 项目根目录 const WEB_ROOT = "/Users/zhoumengkang/Documents/html";}class server { private $ip; private $port; public function __construct($ip, $port) { $this->ip = $ip; $this->port = $port; $this->await(); } private function await() { $sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); if ($sock < 0) { echo "Error:" . socket_strerror(socket_last_error()) . "\n"; } $ret = socket_bind($sock, $this->ip, $this->port); if (!$ret) { echo "BIND FAILED:" . socket_strerror(socket_last_error()) . "\n"; exit; } echo "OK\n"; $ret = socket_listen($sock); if ($ret < 0) { echo "LISTEN FAILED:" . socket_strerror(socket_last_error()) . "\n"; } do { $new_sock = null; try { $new_sock = socket_accept($sock); } catch (Exception $e) { echo $e->getMessage(); echo "ACCEPT FAILED:" . socket_strerror(socket_last_error()) . "\n"; } try { $request_string = socket_read($new_sock, 1024); $response = $this->output($request_string); socket_write($new_sock, $response); socket_close($new_sock); } catch (Exception $e) { echo $e->getMessage(); echo "READ FAILED:" . socket_strerror(socket_last_error()) . "\n"; } } while (TRUE); } /** * @param $request_string * @return string */ private function output($request_string){ // 静态 GET /1.html HTTP/1.1 ... $request_array = explode(" ",$request_string); if(count($request_array) < 2){ return $this->not_found(); } $uri = $request_array[1]; $filename = web_config::WEB_ROOT . $uri; echo "request:".$filename."\n"; // 静态文件的处理 if (file_exists($filename)) { return $this->add_header(file_get_contents($filename)); } else { return $this->not_found(); } } /** * 404 返回 * @return string */ private function not_found(){ $content = "<h1>File Not Found </h1>"; return "HTTP/1.1 404 File Not Found\r\nContent-Type: text/html\r\nContent-Length: ".strlen($content)."\r\n\r\n".$content; } /** * 加上头信息 * @param $string * @return string */ private function add_header($string){ return "HTTP/1.1 200 OK\r\nContent-Length: ".strlen($string)."\r\nServer: mengkang\r\n\r\n".$string; }}$server = new server("127.0.0.1", web_config::PORT);
コードは github https://github.com/zhoumengkang/php/tree/master/php-webserver/static
にアップロードされています上記のコードで述べたように、ファイルがターミナルで実行されている限り、静的 Web サーバーが開始されます。
下の写真は、Web ディレクトリ内の 1.jpg ファイルにアクセスしているときのスクリーンショットです
シンプルな静的 Web サーバーが完成しました。 次の問題は、動的コンテンツの出力をサポートする方法です。 Web サーバー内で特定のプログラムを実行し、結果をクライアントに返すだけでよいのでしょうか?しかし、このようにして、Web サーバーのコードはビジネス コードと結合されます。さまざまなビジネス シナリオで使用できる Web サーバーを解決するにはどうすればよいでしょうか。
CGI の登場により、この問題は解決されました。では、CGIとは何でしょうか?以下の一節をコピーします。
CGI は、外部アプリケーション (CGI プログラム) と Web サーバー間のインターフェース規格であり、CGI プログラムと Web サーバーの間で情報を転送するための手順です。 CGI 仕様により、Web サーバーが外部プログラムを実行し、その出力を Web ブラウザに送信できるようになり、Web の単純な静的ハイパーメディア ドキュメントのセットが完全に新しい対話型メディアに変わります。
めまいがするので、具体的な例を挙げると、たとえば、私たちが使用している PHP グローバル変数 $_SERVER['QUERY_STRING'] は、CGI プロトコルを通じて Web サーバーによって渡されます。たとえば、Nginx では、この fastcgi 設定を覚えているかもしれません
fastcgi_param QUERY_STRING $query_string;
はい、nginx はグローバル変数 $query_string を fastcgi_param の環境変数に渡します。
以下では、CGI の QUERY_STRING をブリッジとして使用し、クライアントから要求された URI 内の情報を CGI プログラムに渡します。 putenv を介してリクエストの環境変数に QUERY_STRING を保存します。
Web サーバーでアクセスされるリソースに .cgi 接尾辞が付いている場合、それは動的アクセスを意味することに同意します。これは、php スクリプトを見つけるために nginx で場所を設定するのと少し似ています。 CGI プログラムをリクエストする必要があるかどうかを確認するのはすべてのルールです。 Web サーバーと区別するために、ユーザー情報を照会する CGI プログラムを C で作成し、ユーザー ID に基づいてユーザー情報を照会します。
大まかなアクセスロジックは以下の通りです
デモコードアドレス: https://github.com/zhoumengkang/php/tree/master/php-webserver/dynamic
デモを実行したい場合は、次のことを行う必要があります
1. config.php
のプロジェクトのルート ディレクトリ WEB_ROOT を変更します。2. cgi-demouser.c をコンパイルし、コマンド gcc -o user.cgi user.c をコンパイルして、ユーザーを追加します。 cgi ファイルを設定したプロジェクトのルート ディレクトリに追加します。 次に3. ターミナルで php start.php を実行して、Web サーバーを起動します
4. http://localhost:9003/user からアクセスできます。 cgi?id=1 と次の効果を確認してください
実際、静的サーバーに基づいていくつかの CGI 判断を行ってリクエストを転送し、github 上の 3 つのファイルのコードを 1 つのファイルにマージして、誰もが共有できるようにしました。見てください