0x00抛砖
1、Web Server传递数据的方法
正式说CGI之前,先来了解一下Web Server传递数据的另外一种方法∶PHP Module加载方式。相信都会想起Apache吧,初学php时,在windows上安装完php和Apache之后,为了让Apache能够解析php代码,我们会在Apache的配置文件(httpd.conf)中添加如下配置∶
#添加下面两行
LoadModule php5_module D: / php/ php5apache2_2.dll
AddType application/ x-httpd-php .php
#修改如下内容
<IfModule dir_module>
DirectoryIndex index.php index.html
</IfModule>
其实原理是,用LoadModule来加载php5_module,就是把php作为apache的一个子模块来运行。当通过web访问php文件时,apache就会调用php5_module来解析php代码。那么,php5_module是如何将数据传给php的解析器来解析php代码的呢?答案是: sapi用一张图来看apache、php、sapi三者之间的关系︰
从上面图中,我们看出了sapi就是这样的一个中间过程,sapi提供了一个和外部通信的接口,使得PHP可以和其他应用进行交互数据((apache,nginx等)。php默认提供了很多种sapi,常见的提供给apache和nginx的php5_module、CGl、FastCGI,给IIS的ISAPI,以及Shell的CLl。(httpd是Apache超文本传输协议(HTTP)服务器的主程序。被设计为一个独立运行的后台进程,它会建立一个处理请求的子进程或线程池)
0x01什么是CGI?
早期的Web服务器,只能响应浏览器发来的HTTP静态资源的请求,并将存储在服务器中的静态资源返回给浏览器。随着Web技术的发展,逐渐出现了动态技术,但是Web服务器并不能够直接运行动态脚本,为了解决Web服务器与外部应用程序(CGI程序)之间数据互通,于是出现了CGI(Common Gateway Interface)通用网关接口。简单理解,可以认为CGI是Web服务器和运行在其上的应用程序进行“交流”的一种约定。
工作原理:
1.CGI针对每个http请求都是fork一个新进程来进行处理,接着读取php.ini文件配置信息,初始化执行环境等。2.然后这个进程会把处理完的数据返回给web服务器,最后web服务器把内容发送给用户。3.刚才fork的进程也随之退出。4.如果下次用户还请求动态资源,那么web服务器又再次fork一个新进程,周而复始的进行。
0x02什么是FastCGI?
有了CGI,自然就解决了Web服务器与PHP解释器的通信问题,但是Web服务器有一个问题,就是它每收到一个请求,都会去Fork一个CGI进程,请求结束再kill掉这个进程,这样会很浪费资源。于是,便出现了CGI的改良版本——Fast-CGI。
维基百科对 FastCGI 的解释是:快速通用网关接口(Fast Common Gateway Interface/FastCGI)是一种让交互程序与Web服务器通信的协议。FastCGI是早期通用网关接口(CGI)的增强版本。FastCGI致力于减少网页服务器与CGI程序之间交互的开销,Fast-CGI每次处理完请求后,不会kill掉这个进程,而是保留这个进程,从而使服务器可以同时处理更多的网页请求。这样就会大大的提高效率
工作原理:
1、Fastcgi则会先fork一个master,解析配置文件,初始化执行环境,然后再fork多个worker。
2、当请求过来时,master会传递给一个worker,然后立即可以接受下一个请求。这样就避免了重复的劳动,效率自然是高。
3、而且当worker不够用时,master可以根据配置预先启动几个worker等着;当然空闲worker太多时,也会停掉一些,这样就提高了性能,也节约了资源。这就是Fastcgi的对进程的管理。大多数Fastcgi实现都会维护一个进程池。注:swoole作为httpserver,实际上也是类似这样的工作方式。
0x03什么是PHP-FPM?
PHP-FPM 就是 PHP 版本的 FastCGI 协议实现,有了它,就是实现 PHP 脚本与 Web 服务器(通常是 Nginx)之间的通信,同时它也是一个 PHP SAPI,从而构建起 PHP 解释器与 Web 服务器之间的桥梁。
工作原理:
PHP-FPM 会创建一个主进程,控制何时以及如何将HTTP请求转发给一个或多个子进程处理。PHP-FPM主进程还控制着什
么时候创建(处理Web应用更多的流量)和销毁(子进程运行时间太久或不再需要了)
PHP子进程。PHP-FPM进程池中的每个进程存在的时间都比单个HTTP请求长,可以处
理10、50、100、500或更多的HTTP请求。
0x04FastCGI协议
FastCGI程序和web服务器之间通过可靠的流式传输(Unix Domain Socket或TCP)来通信,相对于传统的CGI程序,有环境变量和标准输入输出,而FastCGI程序和web服务器之间则只有一条socket连接来传输数据,所以它把数据分成以下多种消息类型:
#define FCGI_BEGIN_REQUEST //表示一个请求的开始
#define FCGI_ABORT_REQUEST // 表示服务器希望终止一个请求
#define FCGI_END_REQUEST //*表示该请求处理完毕
#define FCGI_PARAMS //对应于CGI程序的环境变量,php $_SERVER 数组中的数据绝大多数来自于此
#define FCGI_STDIN //对应CGI程序的标准输入,FastCGI程序从此消息获取 http请求的POST数据
#define FCGI_STDOUT //*对应CGI程序的标准输出,web服务器会把此消息当作html返回给浏览器
#define FCGI_STDERR //*对应CGI程序的标准错误输出, web服务器会把此消息记录到错误日志中
#define FCGI_DATA //这里不做介绍
#define FCGI_GET_VALUES //*这里不做介绍
#define FCGI_GET_VALUES_RESULT //这里不做介绍
#define FCGI_UNKNOWN_TYPE //*FastCGI程序无法解析该消息类型
#define FCGI_MAXTYPE (FCGI_UNKNOWN_TYPE)
注意:由FastCGI程序返回给web服务器的消息类型带有*,剩下的则是由web服务器向FastCGI程序传输的消息类型
然后就是web服务器和FastCGI程序每传输一个消息的时候,首先会传输一个8字节固定长度的消息头:
struct FCGI_Header {
unsigned char version; //表示fastcgi协议版本
unsigned char type; // 表示消息的类型,就是前面提到的多种消息类型之一
unsigned char requestIdB1;//用ID值标识出当前所属的 FastCGI 请求
unsigned char requestIdB0;
unsigned char contentLengthB1;
unsigned char contentLengthB0;
unsigned char paddingLength;//为了使消息8字节对齐,提高传输效率,可以在消息上添加一些字节数来达到消息对齐的目的
unsigned char reserved; //保留字段,暂时无用
/* Body 消息主体 */
unsigned char contentData[contentLength];
unsigned char paddingData[paddingLength];
} FCGI_Record;
头由8个 uchar 类型的变量组成,每个变量一个字节。其中,requestId 占两个字节,一个唯一的标志id,以避免多个请求之间的影响;contentLength 占两个字节,表示 Body 的大小。可见,一个 Fastcgi Record 结构最大支持的 Body 大小是2^16,也就是 65536 字节。后端语言解析了 Fastcgi 头以后,拿到 contentLength,然后再在请求的 TCP 流里读取大小等于 contentLength 的数据,这就是 Body 体。
Body 后面还有一段额外的数据(Padding),其长度由头中的 paddingLength 指定,起保留作用。不需要该Padding的时候,将其长度设置为0即可。
这里我们详细了解一下字节type:type 就是指定该 Record 的作用。因为 Fastcgi 中一个 Record 的大小是有限的,作用也是单一的,所以我们需要在一个TCP流里传输多个 Record,通过 type 来标志每个 Record 的作用,并用 requestId 来标识同一次请求的id。也就是说,每次请求,会有多个 Record,他们的 requestId 是相同的。
看了这个表格就很清楚了,服务器中间件和后端语言通信,第一个数据包就是 type 为1的 Record,后续互相交流,发送 type 为4、5、6、7的 Record,结束时发送 type 为2、3的 Record。
未完待续,有空再补!
声明:本文仅限技术研究与讨论,严禁用于非法用途,否则产生的一切后果自行承担! 本网站采用BY-NC-SA协议进行授权!转载请注明文章来源! 图片失效请留言通知博主及时更改!
大佬yyds