cari
Rumahpembangunan bahagian belakangtutorial phpFastCGI 协议分析以及 FastCGI 在 PHP 中的实现

在讨论 FastCGI 之前,不得不说传统的 CGI 的工作原理,同时应该大概了解 CGI 1.1 协议

传统 CGI 工作原理分析

客户端访问某个 URL 地址之后,通过 GET/POST/PUT 等方式提交数据,并通过 HTTP 协议向 Web 服务器发出请求,服务器端的 HTTP Daemon(守护进程)将 HTTP 请求里描述的信息通过标准输入 stdin 和环境变量(environment variable)传递给主页指定的 CGI 程序,并启动此应用程序进行处理(包括对数据库的处理),处理结果通过标准输出 stdout 返回给 HTTP Daemon 守护进程,再由 HTTP Daemon 进程通过 HTTP 协议返回给客户端。

上面的这段话可能还是比较抽象,下面通过一次GET请求为例说明。

Web 服务器代码

#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <sys/types.h>#include <sys/socket.h>#include <arpa/inet.h>#include <netinet/in.h>#include <string.h>   #define SERV_PORT 9003char* str_join(char *str1, char *str2);char* html_response(char *res, char *buf);  int main(void){    int lfd, cfd;    struct sockaddr_in serv_addr,clin_addr;    socklen_t clin_len;    char buf[1024],web_result[1024];    int len;    FILE *cin;     if((lfd = socket(AF_INET,SOCK_STREAM,0)) == -1){        perror("create socket failed");        exit(1);    }         memset(&serv_addr, 0, sizeof(serv_addr));    serv_addr.sin_family = AF_INET;    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);    serv_addr.sin_port = htons(SERV_PORT);     if(bind(lfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == -1)    {        perror("bind error");        exit(1);    }     if(listen(lfd, 128) == -1)    {        perror("listen error");        exit(1);    }        signal(SIGCLD,SIG_IGN);      while(1)    {        clin_len = sizeof(clin_addr);        if ((cfd = accept(lfd, (struct sockaddr *)&clin_addr, &clin_len)) == -1)        {            perror("接收错误\n");            continue;        }        cin = fdopen(cfd, "r");        setbuf(cin, (char *)0);        fgets(buf,1024,cin); //读取第一行        printf("\n%s", buf);        //============================ cgi 环境变量设置演示 ============================                // 例如 "GET /user.cgi?id=1 HTTP/1.1";        char *delim = " ";        char *p;        char *method, *filename, *query_string;        char *query_string_pre = "QUERY_STRING=";        method = strtok(buf,delim);         // GET        p = strtok(NULL,delim);             // /user.cgi?id=1         filename = strtok(p,"?");           // /user.cgi                if (strcmp(filename,"/favicon.ico") == 0)        {            continue;        }        query_string = strtok(NULL,"?");    // id=1        putenv(str_join(query_string_pre,query_string));        //============================ cgi 环境变量设置演示 ============================        int pid = fork();         if (pid > 0)        {            close(cfd);        }        else if (pid == 0)        {            close(lfd);            FILE *stream = popen(str_join(".",filename),"r");            fread(buf,sizeof(char),sizeof(buf),stream);            html_response(web_result,buf);            write(cfd,web_result,sizeof(web_result));            pclose(stream);            close(cfd);            exit(0);        }        else        {            perror("fork error");            exit(1);        }    }      close(lfd);          return 0;}char* str_join(char *str1, char *str2){    char *result = malloc(strlen(str1)+strlen(str2)+1);    if (result == NULL) exit (1);    strcpy(result, str1);    strcat(result, str2);      return result;}char* html_response(char *res, char *buf){    char *html_response_template = "HTTP/1.1 200 OK\r\nContent-Type:text/html\r\nContent-Length: %d\r\nServer: mengkang\r\n\r\n%s";    sprintf(res,html_response_template,strlen(buf),buf);        return res;}

CGI 程序(user.c)

#include <stdio.h>#include <stdlib.h>// 通过获取的 id 查询用户的信息int main(void){	//============================ 模拟数据库 ============================	typedef struct 	{		int  id;		char *username;		int  age;	} user;	user users[] = {		{},		{			1,			"mengkang.zhou",			18		}	};	//============================ 模拟数据库 ============================	char *query_string;	int id;	query_string = getenv("QUERY_STRING");		if (query_string == NULL)	{		printf("没有输入数据");	} else if (sscanf(query_string,"id=%d",&id) != 1)	{		printf("没有输入id");	} else	{		printf("用户信息查询<br>学号: %d<br>姓名: %s<br>年龄: %d",id,users[id].username,users[id].age);	}		return 0;}

将上面的 CGI 程序编译成 gcc user.c -o user.cgi ,放在上面web程序的同级目录。

FastCGI 工作原理分析

相对于 CGI/1.1 规范在 Web 服务器在本地 fork 一个子进程执行 CGI 程序,填充 CGI 预定义的环境变量,放入系统环境变量,把 HTTP body 体的 content 通过标准输入传入子进程,处理完毕之后通过标准输出返回给 Web 服务器。 FastCGI 的核心则是取缔传统的 fork-and-execute 方式,减少每次启动的巨大开销(后面以 PHP 为例说明),以常驻的方式来处理请求。

FastCGI 与传统 CGI 模式的区别在于 Web 服务器不是直接执行 CGI 程序了,而是通过 socket 与 FastCGI 响应器(FastCGI 进程管理器)进行交互,Web 服务器需要将 CGI 接口数据封装在遵循 FastCGI 协议包中发送给 FastCGI 响应器程序。正是由于 FastCGI 进程管理器是基于 socket 的,所以也是分布式的,Web服务器和CGI响应器服务器分开部署。

FastCGI 协议消息流程

在官方的介绍文档中列举了一些例子 http://www.fastcgi.com/devkit/doc/fcgi-spec.html#SB

下面我们从比较简单的流程入手理解,如下图所示

例如下面的例子

{FCGI_BEGIN_REQUEST,   1, {FCGI_RESPONDER, 0}}{FCGI_PARAMS,          1, "\013\002SERVER_PORT80\013\016SERVER_ADDR199.170.183.42 ... "}{FCGI_STDIN,           1, "quantity=100&item=3047936"}{FCGI_STDOUT,      	 1, "Content-type: text/html\r\n\r\n<html>\n<head> ... "}{FCGI_END_REQUEST,     1, {0, FCGI_REQUEST_COMPLETE}}

FastCGI 请求的各个阶段在 PHP 中的定义

typedef enum _fcgi_request_type {	FCGI_BEGIN_REQUEST		=  1, /* [in]                              */	FCGI_ABORT_REQUEST		=  2, /* [in]  (not supported)             */	FCGI_END_REQUEST		=  3, /* [out]                             */	FCGI_PARAMS				=  4, /* [in]  environment variables       */	FCGI_STDIN				=  5, /* [in]  post data                   */	FCGI_STDOUT				=  6, /* [out] response                    */	FCGI_STDERR				=  7, /* [out] errors                      */	FCGI_DATA				=  8, /* [in]  filter data (not supported) */	FCGI_GET_VALUES			=  9, /* [in]                              */	FCGI_GET_VALUES_RESULT	= 10  /* [out]                             */} fcgi_request_type;

FastCGI 头在 PHP 里的定义

typedef struct _fcgi_header {	unsigned char version;	unsigned char type;	unsigned char requestIdB1;	unsigned char requestIdB0;	unsigned char contentLengthB1;	unsigned char contentLengthB0;	unsigned char paddingLength;	unsigned char reserved;} fcgi_header;

字段解释

version 标识FastCGI协议版本。

type 标识FastCGI记录类型,也就是记录执行的一般职能。

requestId 标识记录所属的FastCGI请求。

contentLength 记录的contentData组件的字节数。

关于上面的 xxB1 和 xxB0 的协议说明:当两个相邻的结构组件除了后缀“B1”和“B0”之外命名相同时,它表示这两个组件可视为估值为B1

比如协议头中 requestId 和 contentLength 表示的最大值就是 65535

#include <stdio.h>#include <stdlib.h>#include <limits.h>int main(){   unsigned char requestIdB1 = UCHAR_MAX;   unsigned char requestIdB0 = UCHAR_MAX;   printf("%d\n", (requestIdB1 << 8) + requestIdB0); // 65535}

FCGI_BEGIN_REQUEST 在 PHP 里的定义

typedef struct _fcgi_begin_request {	unsigned char roleB1;	unsigned char roleB0;	unsigned char flags;	unsigned char reserved[5];} fcgi_begin_request;

Web服务器发送FCGI_BEGIN_REQUEST记录开始一个请求。

字段解释

role 表示Web服务器期望应用扮演的角色。分为三个角色在 PHP 里也有定义

typedef enum _fcgi_role {	FCGI_RESPONDER	= 1,	FCGI_AUTHORIZER	= 2,	FCGI_FILTER		= 3} fcgi_role;

flags 组件包含一个控制线路关闭的位: flags & FCGI_KEEP_CONN :如果为0,则应用在对本次请求响应后关闭线路。如果非0,应用在对本次请求响应后不会关闭线路;Web服务器为线路保持响应性。

FCGI_END_REQUEST 在 PHP 中的定义

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

appStatus 组件是应用级别的状态码。

protocolStatus 组件是协议级别的状态码; protocolStatus 的值可能是:

FCGI_REQUEST_COMPLETE:请求的正常结束。

FCGI_CANT_MPX_CONN:拒绝新请求。这发生在Web服务器通过一条线路向应用发送并发的请求时,后者被设计为每条线路每次处理一个请求。

FCGI_OVERLOADED:拒绝新请求。这发生在应用用完某些资源时,例如数据库连接。

FCGI_UNKNOWN_ROLE:拒绝新请求。这发生在Web服务器指定了一个应用不能识别的角色时。

protocolStatus 在 PHP 中的定义如下

typedef enum _fcgi_protocol_status {	FCGI_REQUEST_COMPLETE	= 0,	FCGI_CANT_MPX_CONN		= 1,	FCGI_OVERLOADED			= 2,	FCGI_UNKNOWN_ROLE		= 3} dcgi_protocol_status;

需要注意 dcgi_protocol_status 和 fcgi_role 各个元素的值都是 FastCGI 协议里定义好的,而非 PHP 自定义的。

Kenyataan
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
PHP vs Python: Memahami PerbezaanPHP vs Python: Memahami PerbezaanApr 11, 2025 am 12:15 AM

PHP dan Python masing -masing mempunyai kelebihan sendiri, dan pilihannya harus berdasarkan keperluan projek. 1.Php sesuai untuk pembangunan web, dengan sintaks mudah dan kecekapan pelaksanaan yang tinggi. 2. Python sesuai untuk sains data dan pembelajaran mesin, dengan sintaks ringkas dan perpustakaan yang kaya.

PHP: Adakah ia mati atau hanya menyesuaikan diri?PHP: Adakah ia mati atau hanya menyesuaikan diri?Apr 11, 2025 am 12:13 AM

PHP tidak mati, tetapi sentiasa menyesuaikan diri dan berkembang. 1) PHP telah menjalani beberapa lelaran versi sejak tahun 1994 untuk menyesuaikan diri dengan trend teknologi baru. 2) Ia kini digunakan secara meluas dalam e-dagang, sistem pengurusan kandungan dan bidang lain. 3) Php8 memperkenalkan pengkompil JIT dan fungsi lain untuk meningkatkan prestasi dan pemodenan. 4) Gunakan OPCACHE dan ikut piawaian PSR-12 untuk mengoptimumkan prestasi dan kualiti kod.

Masa Depan PHP: Adaptasi dan InovasiMasa Depan PHP: Adaptasi dan InovasiApr 11, 2025 am 12:01 AM

Masa depan PHP akan dicapai dengan menyesuaikan diri dengan trend teknologi baru dan memperkenalkan ciri -ciri inovatif: 1) menyesuaikan diri dengan pengkomputeran awan, kontena dan seni bina microservice, menyokong Docker dan Kubernetes; 2) memperkenalkan pengkompil JIT dan jenis penghitungan untuk meningkatkan prestasi dan kecekapan pemprosesan data; 3) Berterusan mengoptimumkan prestasi dan mempromosikan amalan terbaik.

Bilakah anda menggunakan sifat berbanding kelas abstrak atau antara muka dalam PHP?Bilakah anda menggunakan sifat berbanding kelas abstrak atau antara muka dalam PHP?Apr 10, 2025 am 09:39 AM

Dalam PHP, sifat sesuai untuk situasi di mana penggunaan semula kaedah diperlukan tetapi tidak sesuai untuk warisan. 1) Ciri membolehkan kaedah multiplexing dalam kelas untuk mengelakkan pelbagai kerumitan warisan. 2) Apabila menggunakan sifat, anda perlu memberi perhatian kepada konflik kaedah, yang dapat diselesaikan melalui alternatif dan sebagai kata kunci. 3) Tua yang berlebihan harus dielakkan dan tanggungjawab tunggalnya harus dikekalkan untuk mengoptimumkan prestasi dan meningkatkan pemeliharaan kod.

Apakah bekas suntikan ketergantungan (DIC) dan mengapa menggunakan satu dalam PHP?Apakah bekas suntikan ketergantungan (DIC) dan mengapa menggunakan satu dalam PHP?Apr 10, 2025 am 09:38 AM

Kontena Suntikan Ketergantungan (DIC) adalah alat yang menguruskan dan menyediakan kebergantungan objek untuk digunakan dalam projek PHP. Manfaat utama DIC termasuk: 1. Decoupling, membuat komponen bebas, dan kod itu mudah dikekalkan dan diuji; 2. Fleksibiliti, mudah untuk menggantikan atau mengubah suai kebergantungan; 3. Keseluruhan, mudah untuk menyuntik objek mengejek untuk ujian unit.

Terangkan SPL SPLFixedArray dan ciri -ciri prestasinya berbanding dengan susunan PHP biasa.Terangkan SPL SPLFixedArray dan ciri -ciri prestasinya berbanding dengan susunan PHP biasa.Apr 10, 2025 am 09:37 AM

SplfixedArray adalah pelbagai saiz tetap dalam PHP, sesuai untuk senario di mana prestasi tinggi dan penggunaan memori yang rendah diperlukan. 1) Ia perlu menentukan saiz apabila membuat untuk mengelakkan overhead yang disebabkan oleh pelarasan dinamik. 2) Berdasarkan pelbagai bahasa C, secara langsung mengendalikan memori dan kelajuan akses cepat. 3) Sesuai untuk pemprosesan data berskala besar dan persekitaran sensitif memori, tetapi ia perlu digunakan dengan berhati-hati kerana saiznya tetap.

Bagaimana PHP mengendalikan fail memuat naik dengan selamat?Bagaimana PHP mengendalikan fail memuat naik dengan selamat?Apr 10, 2025 am 09:37 AM

PHP mengendalikan fail muat naik melalui pembolehubah fail $ \ _. Kaedah untuk memastikan keselamatan termasuk: 1. Semak kesilapan muat naik, 2. Sahkan jenis dan saiz fail, 3. Mencegah penindasan fail, 4. Pindahkan fail ke lokasi storan tetap.

Apakah pengendali pengendali coalescing null (??) dan pengendali tugasan comelan null (?? =)?Apakah pengendali pengendali coalescing null (??) dan pengendali tugasan comelan null (?? =)?Apr 10, 2025 am 09:33 AM

Dalam JavaScript, anda boleh menggunakan NullcoalescingOperator (??) dan NullcoalescingAssignmentOperator (?? =). 1.? Menerapkan semula operan pertama yang tidak berselisih atau tidak ditentukan. 2.?? Pengendali ini memudahkan logik kod, meningkatkan kebolehbacaan dan prestasi.

See all articles

Alat AI Hot

Undresser.AI Undress

Undresser.AI Undress

Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover

AI Clothes Remover

Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool

Undress AI Tool

Gambar buka pakaian secara percuma

Clothoff.io

Clothoff.io

Penyingkiran pakaian AI

AI Hentai Generator

AI Hentai Generator

Menjana ai hentai secara percuma.

Artikel Panas

R.E.P.O. Kristal tenaga dijelaskan dan apa yang mereka lakukan (kristal kuning)
3 minggu yang laluBy尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Tetapan grafik terbaik
3 minggu yang laluBy尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Cara Memperbaiki Audio Jika anda tidak dapat mendengar sesiapa
3 minggu yang laluBy尊渡假赌尊渡假赌尊渡假赌
WWE 2K25: Cara Membuka Segala -galanya Di Myrise
3 minggu yang laluBy尊渡假赌尊渡假赌尊渡假赌

Alat panas

Muat turun versi mac editor Atom

Muat turun versi mac editor Atom

Editor sumber terbuka yang paling popular

mPDF

mPDF

mPDF ialah perpustakaan PHP yang boleh menjana fail PDF daripada HTML yang dikodkan UTF-8. Pengarang asal, Ian Back, menulis mPDF untuk mengeluarkan fail PDF "dengan cepat" dari tapak webnya dan mengendalikan bahasa yang berbeza. Ia lebih perlahan dan menghasilkan fail yang lebih besar apabila menggunakan fon Unicode daripada skrip asal seperti HTML2FPDF, tetapi menyokong gaya CSS dsb. dan mempunyai banyak peningkatan. Menyokong hampir semua bahasa, termasuk RTL (Arab dan Ibrani) dan CJK (Cina, Jepun dan Korea). Menyokong elemen peringkat blok bersarang (seperti P, DIV),

MantisBT

MantisBT

Mantis ialah alat pengesan kecacatan berasaskan web yang mudah digunakan yang direka untuk membantu dalam pengesanan kecacatan produk. Ia memerlukan PHP, MySQL dan pelayan web. Lihat perkhidmatan demo dan pengehosan kami.

Dreamweaver Mac版

Dreamweaver Mac版

Alat pembangunan web visual

Notepad++7.3.1

Notepad++7.3.1

Editor kod yang mudah digunakan dan percuma