fastcgi协议分析与实例
来源:互联网 发布:unix编程艺术 pdf 编辑:程序博客网 时间:2024/06/10 16:13
1.序言
最近在用c++实现一个简易web服务器。在实现之前大体理了一下一个web服务器主要咋样实现。当时单纯的认为只需要将浏览器发来的http请求解析,找到对应的文件,然后给浏览器一个响应,把其要获取的文件发给它就完事。可是写了没几天就遇到了瓶颈。因为我们的浏览器并不能解析动态的php文件,那么如果获取的http请求的请求文件为.php文件我们该杂么办呢?
2.将.php转换为.html的php-fpm
我们都知道php是一门解释型语言,当php在执行时,php内核都会为我们调用php解释器来帮我们解释程序。而我们的php-fpm相比php内核也具有此功能(事实上,php最新版本以把php-fpm当做一个补丁打在php内核之中了)
php-fpm的安装方式为
sudo apt-get install php5-fpm
显然php-fpm能够帮我们解决1中遇到的问题。具体解决过程为:当我们的web服务器收到.php文件时,就让php-fpm把其解释(翻译)成html格式的文件(事实上php-fpm正是干这个事的),然后我们的web服务器将翻译出来的.html文件发给浏览器就万事大吉了。。
3.php-fpm与webserver交互问题
我想我在2中已经用最少的文字阐述清楚了当我们收到.php文件应该杂么办了。道理的确简单,问题在于我们如何才能让php-fpm帮我们解析我们想要翻译成.html文件的.php文件呢?(要知道php-fpm可不是人,它可听不懂人话的)。为了能与php-fpm愉快的合作,我们就得使用它能听得懂的语言(协议)。说道这fastcgi就正式登场了,没错php-fpm所能听的懂的语言正是fastcgi,我们可以通过fastcgi协议来和php-fpm进行交互来达成我们的目的
4.fastcgi协议
如果读者之前有学习过http或者TCP/IP协议,那么我想通过我接下来简单粗暴的讲解你一定能很快掌握此协议
(1)消息头(请求头)
对于fastcgi这种数据收发协议来说,它所发送的每次请求或是回复(我之后的叙述中叫它们为消息)都有一个可提取的公共部分就是FCGI_Header(请求头),及不管每次发送的是什么消息,都必须会有一个如下格式的请求头
其c语言格式(其支持各种语言)定义如下
typedef struct { unsigned char version; //版本 unsigned char type; //操作类型 unsigned char requestIdB1; //请求id unsigned char requestIdB0; unsigned char contentLengthB1; //内容长度 unsigned char contentLengthB0; unsigned char paddingLength; //填充字节的长度 unsigned char reserved; //保留字节}FCGI_Header;
观察上面的消息请求头我们可以发现一个请求头只有8个字节大小,其每个字段的解释如下
.version:用来表示FCGI的版本信息,如果是web服务器给php-fpm发送的消息,请求头中只需要将其置0就可以
.type:此字段用来说明每次所发送消息的类型,其具体值可以为如下
还有一些其他的不常用的type值,我们这里就不提了,上述type值的详细含义可以在这里获得
戳这里
.requestId:此字段占俩个字节,它表示这某个特有的交互,因为php-fpm(可以理解为服务器)可以同时处理多个交互
.contentLength:此字段也占2个字节,它用来表示此消息中的消息体中数据的长度(我们上面一直说的请求头也可以叫其消息头),我们可以据此在读消息时,能够知道读多长能读出一条完整的消息
.paddingLength:填充长度的值,为了提高处理消息的能力,我们的每个消息大小都必须为8的倍数,此长度标示,我们在消息的尾部填充的长度
.reserved:保留字段
以上便是我们对消息头8字节中每个字节所表达的含义的分析
下图为php-fpm给web服务器传输的一个具体消息的消息头(8字节)内容
.序列0(对应version字段)的数值为01,代表php-fpm的版本信息
.序列1(对应type字段)的数值为03,根据上面对type值含义的解释,可以知道这个消息将标志这此次交互的结束
.序列2,3 00,01说明此次交互的请求ID为01
.序列4,5 00,08标示这在序列7之后的消息体的长度为8
.序列6标示填充字节为0,及本身消息体以是8的字节了
.序列7将消息的保留字节设为0
通过上述具体实例,我想大家大概可以明白当我们得到fastcgi协议的一个消息头,我们能获取那些信息
(2)消息体(请求体)
(1)中我们简单介绍了一个消息的消息头,由于所有的消息都共用这个消息头,所以介绍起来也简单,但是消息体就不同了。对于请求开始(及一次交互的第一个)的消息,有其自己的消息体格式,对于请求结束(一次交互的最后一个)的消息,有其自己的消息体格式,对于传递PARAMS参数……消息头type字段标示的消息类型不同,对应的消息体的格式就可能不同
接下来我会根据type值的不同来介绍各类消息体结构
1.type为1
读者对照上面介绍的type值的含义可知,此类消息为交互刚开始所发的第一个消息,其消息体结构c定义如下
typedef struct { unsigned char roleB1; //web服务器所期望php-fpm扮演的角色,具体取值下面有 unsigned char roleB0; unsigned char flags; //确定php-fpm处理完一次请求之后是否关闭 unsigned char reserved[5]; //保留字段}FCGI_BeginRequestBody;
根据上述可知type值为1的消息(标识开始请求)的消息的消息体为固定大小8字节,其中各个字段的具体含义如下
.role:此字段占2个字节,用来说明我们对php-fpm发起请求时,我们想让php-fpm为我们扮演什么角色(做什么,或理解为杂么做),其常见的3个取值如下:
.flags:字段确定是否与php-fpm建立长连接,为1长连接,为0则在每次请求处理结束之后关闭连接
.reserved:保留字段
2.type值为3
type值为3表示结束消息,其消息体的c定义如下
typedef struct { unsigned char appStatusB3; //结束状态,0为正常 unsigned char appStatusB2; unsigned char appStatusB1; unsigned char appStatusB0; unsigned char protocolStatus; //协议状态 unsigned char reserved[3];}FCGI_EndRequestBody;
同样我们可以看出结束消息体也为固定8字节大小
其各字段的具体含义如下ph
.appStatus:此字段共4个字节,用来表示结束状态,0为正常结束
.protocolStatus:为协议所处的状态,0为正常状态
.reserved:为保留字节
3.type为4
此值表示此消息体为传递PARAMS(环境参数),环境参数其实就是name-value对,我们可以使用自己定义的name-value传给php-fpm或者传递php-fpm已有的name-value对,以下为我们后面实例将会使用到的php-fpm以有的name-value对如下
好了回到主体,当我们要传递消息体为环境参数时,我们的消息体的格式如下
typedef struct { unsigned char nameLengthB3; /* nameLengthB0 >> 7 == 0 */ unsigned char nameLengthB2; unsigned char nameLengthB1; unsigned char nameLengthB0; unsigned char valueLengthB3; /* nameLengthB0 >> 7 == 0 */ unsigned char valueLengthB2; unsigned char valueLengthB1; unsigned char valueLengthB0; unsigned char nameData[(B3 & 0x7f) << 24) + (B2 << 16) + (B1 << 8) + B0]; unsigned char valueData[valueLength ((B3 & 0x7f) << 24) + (B2 << 16) + (B1 << 8) + B0];} FCGI_NameValue;
可以看出消息体前8个字节为固定的,其字段具体含义为
.nameLength:此字段占用4字节,用来说明name的长度
.valueLength:此字段为4个字节,用来说明value的长度
前8个字节之后紧跟的为nameLength长度的name值,接着是valueLength长度的value值
4.type值为5,6,7
当消息为输入,输出,错误时,它的消息头之后便直接跟具体数据
(3)完整消息record
fastcgi将一个完整的消息称为record,我们每次发送的单位就是record。通过上面的介绍,我们可以总结出常见的记录格式
5.fastcgi协议使用实例
前面我们已经介绍了php-fpm的安装方法,其安装好之后,默认的通讯方式为unix本地域套接字通讯,具体查看
/etc/php5/fpm/pool.d/www.conf
截图如下
而我们的接下来的实例与php-fpm为TCP通讯的方式,所以,我们得在这里改下配置,具体修改结果如下所示
我将ip地址设成了127.0.0.1 监听端口设为9000
修改之后需要重启php-fpm进程,如下
sudo service php5-fpm restart
好了准备工作结束,此时编译运行这里的代码,我们就可以将内容为
<html><body><?phpecho "hello";?></body></html>
运行程序结果如下
- fastcgi协议分析与实例
- fastcgi协议分析与实例
- fastcgi协议分析与实例
- FastCGI 协议分析与C语言实现实例
- fastcgi协议分析
- FastCGI协议分析
- SSL/TLS 协议简介与实例分析
- SSL/TLS 协议简介与实例分析
- SSL/TLS 协议简介与实例分析
- Fastcgi协议定义解释与说明
- Fastcgi协议定义解释与说明
- HTTP协议实例分析
- 8583协议实例分析
- 8583协议实例分析
- UDP协议实例分析
- IGMP协议实例分析
- DNS协议实例分析
- php使用fastcgi协议与php-fpm通信
- 10013---CSS Table(表格)
- Find the subarray with least average
- 源码探索系列9---四大金刚之ContentProvider
- Android实战 - 音心播放器 (优化Service退出,按两下退出应用实现)
- 创建版本库
- fastcgi协议分析与实例
- Unity Shader入门介绍
- VBA中Dictionary对象使用小结
- 实战c++中的vector系列--creating vector of local structure、vector of structs initialization
- VBA中dim,static和public,private的区别
- 从程序员的角度看产品经理的逻辑与设计能力
- Git 版本回退/工作区和暂存区
- windows安装mactype启用mac字体渲染
- C++ Primer(十五) 函数