zoukankan      html  css  js  c++  java
  • fastcgi

    nginx和php-fpm是通过fastcgi协议进行通信的,php-fpm本身就是个socket服务端,nginx拿到url后,识别出.php结尾的地址后,会传给php-fpm,php-fpm通过预先启动的进程,调用php解释器

    fastcgi消息有10种,其中有

    fcgi_begin_request

    fcgi_end_request

    fcgi_params //环境变量,QUERY_STRING get后面的数据

    fcgi_stdin //POST数据

    fcgi_stdout //php-fpm返回给nginx的数据

    fcgi_params key value格式 name长度value长度namevalue

    长度小于128,使用一个字节

    长度大于等于128,使用四个字节

    首字节的第1位

    0表示小于128  所以一个字节能表示最大的数字为2的7次方-1=127

    1表示大于等于128, 四个字节能表示的最大的数字为2的31次方-1

     例如name为QUERY_STRING

      value为name=taek&age=20

      那么实际内容为1216QUERY_STRINGname=taek&age=20

    QUERY_STRING的长度为12,12小于128,所以一个字节就能装下了

    12的类型为int,其2进制为

    00000000 00000000 00000000 00001100

    将12强制转为char类型, 就是00001100

    int nameLen=32960;

    char *name="abcdefg....";

    int valueLen=3;

    char *value="abc";

    name的长度为32960, 那么就需要4个字节来装入,value的长度为3,一个字节就能装入

    分配内存 char *p=(char*)malloc(4+1+128+3);

    一.保存nameLen

    32960的二进制为

    第一个字节  第二个字节   第三个字节  第四个字节

    00000000  00000000  10000000  11000000

    1)先右移24位再与0x80做或运算,将最后一个字节的首位置1,并强转为char类型

    00000000 00000000 00000000 00000000

    即*p++ = (char) ( (nameLen>> 24) | 0x80) 保存的是10000000

    2)再右移16位,强转为char

    00000000 00000000 00000000 00000000

    即*p++= (char )( nameLen>> 16) 保存00000000

    3)再右移8位,强转为char类型

    00000000 00000000 00000000 10000000

    即 *p++=(char)(nameLen >>8)

    4) 直接转为char

    11000000

    即 *p++=(char) nameLen;

    p[0] 到p[3]为

     10000000 00000000 10000000  11000000

    二.保存valueLen

    3的二进制为 00000000 00000000 00000000 00000011

    直接强转为char 

    *p++ = (char) valueLen;

    三.保存 name

    while(*name!=''){

      *p++=*name++;

    }

    四。保存value

    while(*value!=''){

      *p++=*value++;

    }

    取数据时, 发现p[0]为10000000,大于等于128, 说明占用四个字节,

    int result =0;

    result = p[0] 即 00000000 00000000 00000000 10000000  

    第一个字节为 result = p[0] << 24 & 0x7f 

    左移24位后为

    100000000 00000000 00000000 00000000 

    再与0x7f做与运算 结果为

    00000000 00000000 00000000 00000000

    第二个字节为 *result |= p[1] << 16 

    左移16位后为

    00000000 00000000 00000000 00000000

    第三个字节为 00000000 00000000 00000000 10000000 左移8位结果为

    00000000 00000000 100000000 00000000

    *result |= p[2] << 8

    第四个字节为*result |= p[3]  

    00000000 00000000 00000000 11000000

    这四个值做或运算 即为

    00000000 0000000 10000000 11000000

    fastcgi 的头类型有以下几种

      

     消息类型

    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;

     消息头

    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组件的字节数。可理解为消息体数据的长度,用两个字节表示,高字节放低地址,低字节放高地址,故每次发送的消息体长度最大不能超过2的16次方-1 = 65535

    FCGI_BEGIN_REQUEST 的定义

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

    role表示Web服务器期望应用扮演的角色。分为三个角色(而我们这里讨论的情况一般都是响应器角色)

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

    FCGI_END_REQUEST 的定义

    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_statusfcgi_role各个元素的值都是 FastCGI 协议里定义好的,而非 PHP 自定义的。

    消息通讯样例

    为了简单的表示,消息头只显示消息的类型和消息的 id,其他字段都不予以显示。下面的例子来自于官网

    {FCGI_BEGIN_REQUEST,   1, {FCGI_RESPONDER, 0}}
    {FCGI_PARAMS,          1, "1302SERVER_PORT801316SERVER_ADDR199.170.183.42 ... "}
    {FCGI_STDIN,           1, "quantity=100&item=3047936"}
    {FCGI_STDOUT,          1, "Content-type: text/html
    
    <html>
    <head> ... "}
    {FCGI_END_REQUEST,     1, {0, FCGI_REQUEST_COMPLETE}}

    配合上面各个结构体,则可以大致想到 FastCGI 响应器的解析和响应流程:

    首先读取消息头,得到其类型为FCGI_BEGIN_REQUEST,然后解析其消息体,得知其需要的角色就是FCGI_RESPONDERflag为0,表示请求结束后关闭线路。然后解析第二段消息,得知其消息类型为FCGI_PARAMS,然后直接将消息体里的内容以回车符切割后存入环境变量。与之类似,处理完毕之后,则返回了FCGI_STDOUT消息体和FCGI_END_REQUEST消息体供 Web 服务器解析。

    参考 https://yq.aliyun.com/articles/58999

    http://redfoxli.github.io/fast-cgi-protocol.html 更细致

  • 相关阅读:
    构建之法阅读心得(九)
    构建之法阅读心得(八)
    构建之法阅读心得(七)
    构建之法阅读心得(六)
    构建之法阅读心得(五)
    构建之法阅读心得(四)
    一组阶段小记之读构建之法(三)
    暑期学习总结
    软工综合实践 学习笔记02
    软工综合实践 学习笔记01
  • 原文地址:https://www.cnblogs.com/taek/p/6368609.html
Copyright © 2011-2022 走看看