FastCgi学总结

最早的Web服务器简单地响应浏览器发来的HTTP请求,并将存储在服务器上的HTML文件返回给浏览器,也就是静态html。随着互联网的不断发展,网站也越来越复杂,所以出现动态技术。但是服务器并不能直接运行 php,asp这样的文件,自己不能做,那就将任务外包给别人,但是要与第三做个约定,我给你发什么,你就得给我回什么,就是我把请求参数发送给你,然后我接收你的处理结果给客户端。那这个约定就是 common gateway interface,简称CGI。这个协议可以用vb,c,php,python 来实现。通常我们的CGI 程序是由服务器进程fork产生子进程,将任务直接抛给子进程做,然后处理完成后
子进程将结果返回给客户端。这样意味着每来一个请求动态网页的连接,就得专门为其开一个进程来处理,这样在并发量小的情况下,倒是可以接受,但是在并发量比较多的时候,计算机肯定是顶不住的。所以我们实现了CGI的增强版本。

快速通用网关接口(Fast Common Gateway Interface/FastCGI)是一种让交互程序与Web服务器通信的协议。FastCGI是早期通用网关接口(CGI)的增强版本。
FastCGI致力于减少网页服务器与CGI程序之间交互的开销,从而使服务器可以同时处理更多的网页请求。

与为每个请求创建一个新的进程不同,FastCGI使用持续的进程来处理一连串的请求。这些进程由FastCGI服务器管理,而不是web服务器。 当进来一个动态请求时,web服务器把环境变量和这个页面请求通过一个socket比如FastCGI进程与web服务器(都位于本地)或者一个TCP connection(FastCGI进程在远端的server farm)传递给FastCGI进程。然后处理完结果又返回给服务器,服务器再返回给客户端。交互流程如下:

在这里插入图片描述
一般FastCgi程序的服务进程是php-fpm服务进程,所以首先得安装php-fpm服务器,Ubuntu安装步骤很简单:

sudo apt-get install php-fpm

然后进入到配置文件,我的系统ubuntu18.10

sudo vim /etc/php/[版本号]/fpm/pool.d/www.conf

找到如下行,按照以下方式修改,也就是指定一个监听的IP+端口:

在这里插入图片描述
然后退出,制定php-fpm版本号,我的执行命令是php-fpm7.2。
我的测试是否成功:

telnet 127.0.0.1 9000

能连上表名成功安装。

安装成功了,下面我们来分析这个协议是如何工作的,并加以实践。

  • FCGI_BEGIN_REQUEST

Web服务器与FastCgi可以通过网络套接字进行通信,也可以通过Unix域套接字进行通信。
先看消息头:

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;
};

上面命名见名知意,不解释是啥了,下面分析其作用吧。
version 一般设置为版本为1,type表示数据包类型。值的空间:

enum FCGI_Type {
   // (WEBServer->FastCGI) 表示一次请求的开始
  FCGI_BEGIN_REQUEST     = 1, 
  // (WEBServer->FastCGI) 表示终止一次请求
   FCGI_ABORT_REQUEST     = 2,
     // (FastCGI->WEBServer) 请求已被处理完毕  
  FCGI_END_REQUEST       = 3,
  // (WEBServer->FastCGI) 表示一个向CGI程序传递的环境变量
  FCGI_PARAMS            = 4,
  // (WEB->FastCGI) 表示向CGI程序传递的标准输入  
  FCGI_STDIN             = 5,  
   // (FastCGI->WEB) 表示CGI程序的标准输出 
  FCGI_STDOUT            = 6, 
  // (FastCGI->WEBServer) 表示CGI程序的标准错误输出  
  FCGI_STDERR            = 7,  
     // (WEBServer->FastCGI) 向CGI程序传递的额外数据
   FCGI_DATA              = 8,
 // (WEB->FastCGI) 向FastCGI程序询问一些环境变量
   FCGI_GET_VALUES        = 9,
   // (FastCGI->WEB) 询问环境变量的结果
   FCGI_GET_VALUES_RESULT = 10,
   // 未知类型,可能用作拓展 
    FCGI_UNKNOWN_TYPE      = 11  
};

requestIdB0和requestIdB1是合起来表示本次请求的编号,其中requestIdB1是请求标号的高八位,requestIdB0是请求的低八位,这个字段的存在允许Web服务器在一次连接中向FastCgi服务器发送多个不同的请求,只要使用不同编号的请求就行。然后contentLengthB1, contentLengthB0和起来表示消息头后仍有多少个字节的数据,contentLengthB1表示其高八位,B2表示其第八位,总共和起来数据字节大小刚好在0~65535之间,如果数据包太大超过65535就需要分多个数据包传输,第七个字节为填充长度,保证字节对齐。第八个字节为保留字段。目前还没用到过。下面是构造头的过程:

  FCGI_Header FastCgi::makeHeader(int type,int requestId,int contentLength,int paddingLength)
  {
      FCGI_Header header;
      header.version = FCGI_VERSION_1;
      header.type    = (unsigned char)type;   
          
      header.requestIdB1 = (unsigned char)((requestId >> 8) & 0xff);  //用两个字段保存请求ID
      header.requestIdB0 = (unsigned char)(requestId & 0xff);
    
      header.contentLengthB1 = (unsigned char)((contentLength >> 8) & 0xff);//用两个字段保存内容长度
      header.contentLengthB0 = (unsigned char)(contentLength & 0xff);
      
      header.paddingLength = (unsigned char)paddingLength;        //填充字节的长度
      header.reserved = 0;    //保留字节赋为0  
      return header;
  }

消息体:

typedef struct 
{
    unsigned char roleB1;       //web服务器所期望php-fpm扮演的角色,具体取值下面有
    unsigned char roleB0;
    unsigned char flags;        //确定php-fpm处理完一次请求之后是否关闭
    unsigned char reserved[5];  //保留字段
}FCGI_BeginRequestBody;

其中roleB0和roleB合起来表示web服务器请求CGI程序在程序中担当的角色。
具体取值:

enum FCGI_Role {
  FCGI_RESPONDER  = 1,  // 响应器
  FCGI_AUTHORIZER = 2,  // 认证器
  FCGI_FILTER     = 3   // 过滤器
};

一般FastCgi程序做的就是响应器。第三个字节表示的是web服务器想让FastCgi处理完请求后的行为,比如发完请求关闭连接还是保持连接,1为不关闭,否则为关闭。其他字节还用不到。

  • FCGI_END_REQUEST

消息题还是固定的八字节结构体,因此该类型的消息头中表示数据长度的字段也应当是固定的。格式被定义为

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

前四字节表示CGI程序的退出状态,与之前的相同,此处是一个网络字节序,需要手动转换,第五子节表示FastCGI协议的状态码,取值如下:

enum FCGI_ProtocolStatus {
  FCGI_REQUEST_COMPLETE = 0,  // 请求正常完成
  FCGI_CANT_MPX_CONN    = 1,  // FastCGI服务器不支持并发处理,请求已被拒绝
  FCGI_OVERLOADED       = 2,  // FastCGI服务器耗尽了资源或达到限制,请求已被拒绝
  FCGI_UNKNOWN_ROLE     = 3   // FastCGI不支持指定的role,请求已被拒绝
};

后面的字节尚无作用。

  • FCGI_PARAMS

消息体格式:

struct FCGI_ParamsBody {
  unsigned char nameLengthB3;
  unsigned char nameLengthB2;
  unsigned char nameLengthB1;
  unsigned char nameLengthB0;
  unsigned char valueLengthB3;
  unsigned char valueLengthB2;
  unsigned char valueLengthB1;
  unsigned char valueLengthB0;
  unsigned char nameData[NAME_LENGTH];    // NAME_LENGTH与前四字节所表示数字相同
  unsigned char valueData[VALUE_LENGTH];  // VALUE_LENGTH与第五到八字节所表示的数字相同
};

消息体格式的前四字节表示传给FastCGI的环境参数名的长度,第五到第八字节的则表示环境值的长度,在这八字节之后,先跟环境参数名,再跟相应的环境值。

下面是Web服务器向FCGI程序发送GET请求的流程:

在这里插入图片描述
下面是示例的代码,感谢fork和star!?
代码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值