CGIの基本原則とボトムの基本的な実現について話す

歴史的起源:
初期のWebサーバーは、ブラウザーからのHTTP静的リソース要求にのみ応答し、サーバーに格納されている静的リソースをブラウザーに返すことができました。Webテクノロジーの発展に伴い、動的テクノロジーが徐々に登場しましたが、Webサーバーは動的スクリプトを直接実行できません。Webサーバーと外部アプリケーション(CGIプログラム)間のデータ相互通信を解決するために、CGI(Common Gateway Interface)が登場しました。ゲートウェイインターフェイス。簡単に理解すると、CGIは、Webサーバーとその上で実行されているアプリケーションとの間の「通信」の規則と考えることができます。

簡単に言えば、CGIは、Webサーバー上で動的ページコンピューティングを実行する一種の外部ロジックコンピューティング拡張プログラムです(Webサーバーとcgiプログラム間のデータ交換はTCPプロトコルに基づいています)。

基本原則:
CGIの基本的な考え方は、標準入力(STDINT)、標準出力(STDOUT)、および標準エラー(STDERR)をWebサーバーとcgi外部プログラムのtcp接続にリダイレクトし、次に標準入力およびプロセス環境変数Webサーバーによって入力されたデータを読み取り、stdoutおよびstderrorにパラメーターを書き込んで、標準データの相互作用を実行します。CGIは、Webサーバーと独立したプロセス間のプロトコルです。HTTP要求のヘッダーヘッダーをプロセスの環境変数に設定し、HTTP要求の本文をプロセスの標準入力に設定し、プロセスの標準出力は、ヘッダーと本文を含むHTTP応答応答に設定されます。

実装のアイデア:
Linuxでdupとdup2の2つのAPIを使用して、ファイル記述子をコピーし、リダイレクトを実現します。ここでは、stdout変数と環境変数のみを紹介します。stdinとstderrorのみが同じ原理を持っています。

#include<unistd.h>
int dup(int oldfd);
int dup2(int oldfd,int newfd);
   当调用dup函数时,内核在进程中创建一个新的文件描述符,此描述符是当前可用文件描述符的最小数值,这个文件描述符指向oldfd所拥有的文件表项。 
  dup2和dup的区别就是可以用newfd参数指定新描述符的数值,如果newfd已经打开,则先将其关闭。如果newfd等于oldfd,则dup2返回newfd, 而不关闭它。dup2函数返回的新文件描述符同样与参数oldfd共享同一文件表项。
  APUE用另外一个种方法说明了这个问题: 
  实际上,调用dup(oldfd)等效于,fcntl(oldfd, F_DUPFD, 0) 
  而调用dup2(oldfd, newfd)等效于,close(oldfd)fcntl(oldfd, F_DUPFD, newfd)
server关键代码
 int connfd = accept(sock,(struct sockaddr*)&client,&len);
 if(connfd < 0)
   printf("errno is:%d\n",errno);
 else 
 {
    
    
    close(STDOUT_FILENO);//关闭标准输出后dup返回的就是最小值stdout_fileno
    dup(connfd);
    printf("test cgi ret!\n");
 }

client端代码

 if((connect(sock,(struct sockaddr*)&client,sizeof(client)) != -1))
 {
    
    
  char buf[30];
  printf("connect successful!\n");
  if(recv(sock,buf,sizeof(buf),0) > 0)
  	cout<<buf<<endl;
 }

运行结果:
connect successful!
test cgi ret!

cgiが入力を取得する別の方法は、Webサーバーによってcgiプロセスに設定されたプロセス環境変数です。実際、環境変数に対応する値は、cgiのgetenv関数を介して取得されます。

while (FCGI_Accept() >= 0)
{
    
    
//如果想得到数据,需要从stdin 去读,实际上从Nginx 上去读
//如果想上传数据,需要往stdout 写,实际上是给Nginx 写数据
printf("Content-type: text/html\r\n");
printf("\r\n");
printf("<title>Fast CGI Hello!</title>");
printf("<h1>Fast CGI Hello!</h1>\n");
//请求次数
printf("Request number %d <br>\n", ++count);
//SERVER_NAME:得到server 的host 名称
printf("SERVER_NAME:%s <br>\n", getenv("SERVER_NAME"));
//SERVER_PORT:得到server 的post 名称
printf("SERVER_PORT:%s <br>\n", getenv("SERVER_PORT"));
//获取客户端参数
printf("QUERY_STRING:%s <br>\n", getenv("QUERY_STRING"));
}

既存の利点と必要性:

必要性:初期のWebサーバーは、ブラウザーから送信されたHTTP静的リソース要求にのみ応答し、サーバーに格納されている静的リソースをブラウザーに返すことができました。ページの動的計算はできませんでした。CGIは外部拡張プログラムを使用しました。httpの問題を解決しました。動的ページ

安定性:
fastcgiはcgiを別のプロセスプールで実行し、単一のプロセスが停止し、システムはそれを簡単に破棄してから、新しいプロセスを再配布してロジックを実行できます

セキュリティ:
fastcgiとホストサーバーは完全に独立しており、fastcgiがどれだけダウンしても、サーバーは破壊されません。

パフォーマンス:
fastcgiは動的ロジックの処理をサーバーから分離し、重いIO処理はホストサーバーに任されるため、ホストサーバーはIOに集中できます。通常の動的Webページの場合、ロジック処理はごくわずかです。一部。多数の画像などの静的IO処理では、ロジックプログラムの参加はまったく必要ありません。

拡張性:
fastcgiは中立的な技術標準であり、任意の言語(php、java、python ...)で記述されたプログラムの処理を完全にサポートできます。

言語の独立性:
CGIはどの言語からも独立しています。CGIプログラムは、その言語がこのシステムで実行できる限り、任意のスクリプト言語または完全に独立したプログラミング言語で実装できます。Unixシェルスクリプト、Python、Ruby、PHP、perl、Tcl、C / C ++、およびVisual Basicはすべて、CGIプログラムの作成に使用できます。

動的ページデータを要求するブラウザの全体的な基本プロセス:

  1. ユーザー要求はインターネット経由でWebサーバーに送信されます
    2)Webサーバーはユーザー要求を受信して​​CGIプログラムに配信します
    3)CGIプログラムは処理結果を
    Webサーバーに送信します4)Webサーバーは結果を送り返しますユーザーに
    ここに画像の説明を挿入

ここに画像の説明を挿入
CGIの
短所短所:1プロセスの1リクエスト処理方法では、プロセスの作成と破棄を頻繁に行う必要があるため、Webサーバーの効率が低下し、サーバーシステムのリソース使用量が大きくなります。
ここに画像の説明を挿入

Fastcgiの改善:
ここに画像の説明を挿入
FastCGI
高速共通ゲートウェイインターフェイス(FastCommonGatewayInterface / FastCGI)は、クライアントプログラムとサーバープログラム間のデータ転送の標準を説明する共通ゲートウェイインターフェイス(CGI)の改善です。FastCGIは、サーバーがより多くのWeb要求を同時に処理できるように、WebサーバーとCGIプログラム間の対話のコストを削減することに取り組んでいます。リクエストごとに新しいプロセスを作成するのとは異なり、FastCGIは連続プロセスを使用して一連のリクエストを処理します。これらのプロセスは、Webサーバーではなく、FastCGIプロセスマネージャーによって管理されます。

FastCGIとは何ですか?
FastCGIは、言語に依存しないスケーラブルなアーキテクチャのCGIオープン拡張機能です。その主な動作は、管理とスケジューリングのためにCGIインタープリタープロセスをメモリに保持することです。これにより、より高いパフォーマンスを実現できます。

FastCGIワークフロー
ここに画像の説明を挿入

  1. Webサーバーの起動時にFastCGIプロセスマネージャーをロードする
  2. FastCGIプロセスマネージャーはそれ自体を初期化し、複数のCGIインタープリタープロセスを開始し、Webサーバーからの接続を待ちます
  3. クライアント要求がWebサーバーに到着すると、FastCGIプロセスマネージャーが選択してCGIインタープリターに接続します。4)FastCGIサブプロセスが処理を終了した後、標準出力とエラーメッセージが同じ接続からWebサーバーに返されます。

FastCGIプロトコル
FastCGIでは、各HTTP要求(または応答)メッセージは送信のためにいくつかのレコード(レコード)に分割され、各レコードはヘッダー(ヘッダー)とデータ(ボディ)で構成されます。
メッセージパッシングにRecordを使用する利点:
•複数の要求されたデータを同じ接続で再利用して送信できるため、アプリケーションの実装でイベント駆動型プログラミングモデルまたはマルチスレッドプログラミングモデルを採用して効率を向上させることができます。
•同じ要求で複数のデータストリームのデータを異なるレコードにカプセル化して、同じ接続で送信できます。たとえば、STDOUTとSTDERRの2つの出力ストリームのデータは、2つの接続を使用する代わりに、同じ接続を介してWebサーバーに返すことができます。 。

Record 结构体
typedef struct {
    
     /* Header */
unsigned char version; // FastCGI版本 
unsigned char type; // 当前 Record 的类型 
unsigned char requestIdB1; // 当前 Record对应的请求 id (通过 requestId 来识别请求) 
unsigned char requestIdB0; 
unsigned char contentLengthB1; // 当前 Record 中 Body 体数据的长度 
unsigned char contentLengthB0; 
unsigned char paddingLength; // Body 中填充块的长度 
unsigned char reserved; /* Body */ 
unsigned char contentData[contentLength]; // Body 体数据 
unsigned char paddingData[paddingLength]; // Body 中填充块长度 
} FCGI_Record;

FastCGIプロトコルタイプ
FastCGIは、バイナリ連続送信であり、メッセージパケットの切断を容易にするために、各メッセージのメッセージ本文を読み取るために使用されるメッセージヘッダーの統一された構造を定義します。通常、FCGI_BEGIN_REQUESTタイプのメッセージが最初に送信され、次にFCGI_PARAMSおよびFCGI_STDINタイプのメッセージが送信されます。FastCGI応答が処理されると、FCGI_STDOUTおよびFCGI_STDERRタイプのメッセージが送信され、最後にFCGI_END_REQUESTが要求の終了を示します。FCGI_BEGIN_REQUESTとFCGI_END_REQUESTは、それぞれリクエストの開始と終了を表し、契約全体に関連しています。

#define FCGI_BEGIN_REQUEST 1 //(web->fastcgi)请求开始数据包 
#define FCGI_ABORT_REQUEST 2 //(web->fastcgi)终止请求 
#define FCGI_END_REQUEST 3 //(fastcgi->web)请求结束 
#define FCGI_PARAMS 4 //(web->fastcgi)传递参数 
#define FCGI_STDIN 5 //(web->fastcgi)数据流传输数据 
#define FCGI_STDOUT 6 //(fastcgi->web)数据流传输数据 
#define FCGI_STDERR 7 //(fastcgi->web)数据流传输 
#define FCGI_DATA 8 //(web->fastcgi)数据流传输 
#define FCGI_GET_VALUES 9 //(web->fastcgi)查询 fastcgi 服务器性能参数 
#define FCGI_GET_VALUES_RESULT 10 //(fastcgi->web)fastcgi 性能参数查询返回 #define FCGI_UNKNOWN_TYPE 11 
#define FCGI_MAXTYPE (FCGI_UNKNOWN_TYPE)

** WebサーバーがFastCGI要求を送信する場合:** 3種類のレコードを順番に送信します。タイプは、BEGIN_REQUEST、PARAMS、およびSTDINFastCGIです。

**プロセスがFastCGI応答を返す場合:** 3種類のレコードを順番に返します。種類はSTDOUT、STDERR、END_REQUESTです。

FastCGIリクエスト配信プロセス:

ここに画像の説明を挿入
WebサーバーからFastCGIプログラムに送信されるメッセージタイプは次のとおりです
。FCGI_BEGIN_REQUESTは要求の開始を
示しFCGI_ABORT_REQUESTはサーバーが要求の終了を希望することを示しますFCGI_PARAMSは
CGIプログラムの環境変数に対応し、ほとんどのデータphp $ _SERVER配列は、CGIプログラムの標準入力に対応します。FastCGI
プログラムは、このメッセージからhttpリクエストのPOSTデータを取得します。また、
FCGI_DATAとFCGI_GET_VALUESはここでは紹介されていません。

FastCGIプログラムによってWebサーバーに返されるメッセージタイプは次のとおりです
。FCGI_STDOUTはCGIプログラムの標準出力に対応し、Webサーバーはこのメッセージをhtmlとして
CGIプログラムの標準エラー出力に対応するブラウザーFCGI_STDERRに返します。 、およびWebサーバーはこれを出力します。メッセージはエラーログに記録されます
。FCGI_END_REQUESTは要求が処理されたことを示します
。FCGI_UNKNOWN_TYPEFastCGIプログラムはメッセージタイプを解析できません。さらに、ここでは紹介されないFCGI_GET_VALUES_RESULTもあります。

FastCGIデータパケット形式
FastCGIデータパケットには、ヘッダー(ヘッダー)と本文(本文)の2つの部分があります。各データパケットにはヘッダーが含まれている必要があり、本文がなくてもかまいません。ヘッダーは8バイトで、本文は8の整数倍である必要があります。そうでない場合は、入力する必要があります。

typedef struct {
    
     
unsigned char version; // 版本号 
unsigned char type; // 数据包类型 
unsigned char requestIdB1; // 记录 id 高 8 位 
unsigned char requestIdB0; // 记录 id 低 8 位 
unsigned char contentLengthB1; // 记录内容长度高 8 位(body 长度高 8 位) 
unsigned char contentLengthB0; // 记录内容长度低 8 位(body 长度低 8 位) 
unsigned char paddingLength; // 补齐位长度(body 补齐长度) 
unsigned char reserved; // 补齐位 
}FCGI_Header;

パケット本体の
FCGI_BEGIN_REQUESTタイプレコードのcontentDataデータ部分の構造:

typedef struct {
    
     unsigned char roleB1; unsigned char roleB0; unsigned char flags; unsigned char reserved[5]; } FCGI_BeginRequestBody;
typedef struct {
    
     FCGI_Header header; FCGI_BeginRequestBody body; } FCGI_BeginRequestRecord;

FCGI_END_REQUESTタイプのレコードのcontentDataデータ部分の構造:

typedef struct {
    
     
unsigned char appStatusB3; 
unsigned char appStatusB2; 
unsigned char appStatusB1; 
unsigned char appStatusB0; 
unsigned char protocolStatus; 
unsigned char reserved[3]; 
} FCGI_EndRequestBody;

typedef struct {
    
     
FCGI_Header header; 
FCGI_EndRequestBody body; 
} FCGI_EndRequestRecord;
typedef struct {
    
     
unsigned char type; 
unsigned char reserved[7]; 
} FCGI_UnknownTypeBody;

typedef struct {
    
     
FCGI_Header header; 
FCGI_UnknownTypeBody body; 
} FCGI_UnknownTypeRecord;

FastCGI構成パラメーターと環境変数
FastCGI構成パラメーター

Nginxは、モジュールngx_http_fastcgi_moduleに基づいて、指定されたクライアント要求をspawn-fcgiに転送し、fastcgiプロトコルで処理します。

//转发请求到后端服务器,address 为后端的 fastcgi server 的地址,可用位置:location, if in location。 
fastcgi_pass address; 
//fastcgi默认的主页资源,示例:fastcgi_index index.html;这个功能和 index index.html 功能一样。 
fastcgi_index name; 
//设置传递给 FastCGI 服务器的参数值,可以是文本,变量或组合,可用于将 Nginx 的内置变量赋值给自定义 key fastcgi_param parameter value [if_not_empty]; //调用指定的缓存空间来缓存数据,可用位置:http, server, location;zone 的值为 keys_zone 定义好的缓存名称。 
fastcgi_cache zone|off; //定义用作缓存项的 key 的字符串,示例:fastcgi_cache_key $request_uri; 针对用户请求的 uri 进行缓存。 
fastcgi_cache_key string; 
//为哪些请求方法使用缓存。 
fastcgi_cache_methods GET|HEAD|POST...; 
//缓存空间中的缓存项在 inactive 定义的非活动时间内至少要被访问到此处所指定的次数方可被认作活动项,如果不够命中所指定的缓存次数为非活动项,会将被从缓存中清除。 fastcgi_cache_min_uses number; 
//收到后端服务器响应后,fastcgi 服务器是否关闭连接,建议启用长连接。这个功能需要开启,spawn 处理完这次请 求后,如果和 nginx 断开链接,下次用户再次发起请求,nginx 还需要和 spawn 先三次握手建立连接;开启之后,nginx 和 spawn 不断开连接,省略了建立连接的过程。 fastcgi_keep_conn on|off; 
//不同的响应码各自的缓存时长;200 的缓存时长需要长一些,404 的缓存时长短一些。 fastcgi_cache_valid 200 10m; 
//隐藏后端 spawn 服务器的响应头指定信息。 
fastcgi_hide_header field;

FastCGI環境変数

SCRIPT_FILENAME $document_root$fastcgi_script_name;#脚本文件请求的路径 QUERY_STRING $query_string; #请求的参数;?app=123 
REQUEST_METHOD $request_method; #请求的动作(GET,POST) 
CONTENT_TYPE $content_type; #请求头中的 Content-Type 字段 
CONTENT_LENGTH $content_length; #请求头中的 Content-length 字段。
SCRIPT_NAME $fastcgi_script_name; #脚本名称 
REQUEST_URI $request_uri; #请求的地址不带参数 
DOCUMENT_URI $document_uri; #与$uri 相同。 
DOCUMENT_ROOT $document_root; #网站的根目录。在 server配置中 root 指令中指定的值 SERVER_PROTOCOL $server_protocol; #请求使用的协议,通常是 HTTP/1.0 或 HTTP/1.1。 GATEWAY_INTERFACE CGI/1.1;#cgi 版本 
SERVER_SOFTWARE nginx/$nginx_version;#nginx 版本号,可修改、隐藏 
REMOTE_ADDR $remote_addr; #客户端 IP REMOTE_PORT $remote_port; #客户端端口 SERVER_ADDR $server_addr; #服务器 IP 地址 SERVER_PORT $server_port; #服务器端口 SERVER_NAME $server_name; #服务器名,域名在 server 配置中指定的 server_name PATH_INFO $path_info;#可自定义变量

5.のFastCGIプロセスマネージャ
5.1のFastCGIプロセスマネージャの
FastCGIはFastCGIのと、サーバーがnginxの下に分離されている(多くの異なる種類があり、FastCGIプロセスマネージャ)を管理するためのspawn-fcgiのか、PHP-FPMを使用することができます
5.2spawn-fcgiの
5.2.1spawn何が- fcgiはしますか?

•これはかなりのプロキシツールです
•役割はnginxとfastcgiの間のプロセス間通信を完了し
ます5.2.2環境構成
•nginxが処理できない命令は処理のためにfastcgiに渡されます
•データを転送する必要があり
ます•データは指定されたポートに送信されます
•命令テストを処理し
ます•url:http://192.168.52.139/test

location /test{
    
    
 #配置 fastcgi 模块 
 fastcgi_pass 127.0.0.1:9001; 
 	#IP: 
		#127.0.0.1/localhost/192.168.52.139 
 	#端口: 
 		#将要处理的数据发送到 9001 端口 
 	#9001 端口对应一个进程, 该进程可以收到 nginx 发送过来的数据 
 include fastcgi.conf; 
 }

5.2.3spawn-fcgiの使用
○fcgiプログラムによってコンパイルされたプログラム名テストを記述します
○spawn-fcgi-aIP-pport-ffastcgiプログラムパラメータの説明:
-a IP:サーバーIPアドレス
-pポート:サーバーはポートにデータを送信します-
f cgiプログラム:spawn-fcgiによって開始された実行可能なfastcgiプログラム

5.2.4 fastCGIプロトコル、Spawn-fcgi、およびNginxの関係
NginxはWebサーバーであり、HTTPプロトコルの入力と出力のみを提供します。
spawn-fcgiサーバーは、Fastcgiプロトコルの入力と出力のみをサポートします。
それらの2つは、NginxによってHTTPプロトコルからFastcgiプロトコルに直接変換され、処理のためにfastCGIプロセスに送信されます。

FastCGI、Spawn-fcgi、およびNginxは、
ここに画像の説明を挿入
ユーザーリクエストプロセス
ここに画像の説明を挿入
6に関連しています。http_fastcgi_modulenginx
サービスは、動的リクエストを迅速かつ効率的に処理できるFastCGIモードをサポートしています。nginxに対応するFastCGIモジュールはngx_http_fastcgi_moduleです。

ngx_http_fastcgi_moduleモジュールを使用すると、リクエストをFastCGIサーバーに渡すことができます。httpプロトコルをfastcgiプロトコルに変換する

6.1ngx_http_fastcgi_moduleモジュール構成

//address是 fastcgi server 监听的 IP 地址和端口; 
//示例:fastcgi_pass 127.0.0.1:9000; 
1. fastcgi_pass address;:指明反向代理的服务器
//示例:fastcgi_index index.php; 
2.fastcgi_index# ;:定义 fastcgi 应用的默认主页; 
//设定传递给后端 fastcgi server 参数及其值; //示例:fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
///index.php ---> /scripts/index.php
3.fastcgi_paramparameter value [if_not_empty];//定义缓存:缓存空间等;应用于 http 配置段。 
//------------------------------------------------------------------------------------------------| 
//--|path | 数据缓存在磁盘中位 置 | 
//--|levels=#[:#[:#]] | 定义的目录级别,levels=2:1表示两位十六进制字符命名目录,每个目录中还有目 录 | 
//--|keys_zone=name:size| 元数据缓存在内存中;name;cache 的标识符;size:元数据 cache 大 小; | 
//--|inactive=time | 缓存的非活动时 间 | 
//--|max_size | 缓存空间上 限 | 
//-----------------------------------------------------------------------------------------------4.fastcgi_cache_pathpath [levels=levels][use_temp_path=on|off] keys_zone=name:size [inactive=t ime][max_size=size];
//调用定义过的缓存; //zone即为通过 fastcgi_cache_path 定义缓存时其 keys_zone参数中的 name; 
3. fastcgi_cachezone | off;
//定义如何使用缓存键; 
//示例:fastcgi_cache_key $request_uri; 
4. fastcgi_cache_keystring;
//为何请求方法对应的请求进行缓存,默认为 GET 和 HEAD; 
5. fastcgi_cache_methods GET | HEAD | POST ...;
//缓存项的最少使用次数; 
6. fastcgi_cache_min_usesnumber;
//是否可使用 stale 缓存项响应用户请求; 
7. fastcgi_cache_use_staleerror | timeout | invalid_header | updating | http_500 | http_503 | http_403 |http_404 | off ...;
//对不同响应码的响应设定其可缓存时长; 10.fastcgi_cache_valid[code ...] time;

6.2ngx_http_fastcgi_module詳細情報
詳細情報:http:
//nginx.org/en/docs/http/ngx_http_fastcgi_module.html6.3nginx構成
○場所の場所の追加/ group1 / M00

location /group1/M00 {
    
     
	///home/milo/fastdfs/storage/fastdfs0/data - fastDFS 的 storage 存储数据的真实目录 
	root /home/milo/fastdfs/storage/fastdfs0/data; 
	//fastdfs 模块的名字 
	ngx_fastdfs_module; 
	}

○nginxの設定ファイルをリロードします

6.3 mod_fastdfs.conf構成ファイル
は、変更するために現在のストレージノードストレージ構成ファイルを参照する必要があります

○ log 日志目录 § base_path=/home/milo/fastDFS/storage 
○ 追踪器的地址 § tracker_server=192.168.52.139:22122 
○ 当前存储节点的端口 § storage_server_port=23000 
○ 当前存储节点所属的组 § group_name=group1 
○ 浏览器访问的时候, url 中是否包含组名 § url_have_group_name = true 
○ 当前存储节点存储路径的个数 § store_path_count=1 
○ 当前存储节点的存储路径 
	§ store_path0=/home/milo/fastDFS/storage/fastdfs0 
		□ 如果有多个, 需要全部写到配置文件中 
		® store_path1 
		® store_path2 
○ 整个的 fastDFS 文件系统一共有多少个组 § group_count = 1 
○ 每个组的信息 [group1] group_name=group1 storage_server_port=23000
store_path_count=1 
store_path0=/home/milo/fastDFS/storage/fastdfs0

おすすめ

転載: blog.csdn.net/wangrenhaioylj/article/details/108973076