【lom599乐百家手机】协议以及在,协议的运行原理

 百家乐-前端     |      2020-01-10 18:06

在研讨 FastCGI 以前,不得不说古板的 CGI 的行事规律,同有时候应该大致领会 CGI 1.1 协议

目录

守旧 CGI 工作规律分析

客商端访问有些 U奥迪Q7L 地址然后,通过 GET/POST/PUT 等艺术提交数据,并透过 HTTP 左券向 Web 服务器发出恳求,服务器端的 HTTP Daemon(守护进度)将 HTTP 诉求里描述的音信经过正式输入 stdin 和碰到变量(environment variableState of Qatar传递给主页钦定的 CGI 程序,并运维此应用程序进行拍卖(包含对数据库的管理),管理结果通过规范输出 stdout 重返给 HTTP Daemon 守护进程,再由 HTTP Daemon 进程经过 HTTP 公约再次回到给客商端。

下边的这段话理解可能照旧相比空虚,下边大家就因而叁回GET诉求为例实行详细表达。

百家了乐八大技巧 1

上面用代码来贯彻图中公布的意义。Web 服务器运转贰个 socket 监听服务,然后在地点试行 CGI 程序。后边有相比较详细的代码解读。

  • 介绍
  • 深入CGI协议
    • CGI的运作规律
    • CGI商讨的劣点
  • 深入FastCGI协议
    • 法斯特CGI左券运营规律
    • lom599乐百家手机 ,为啥是 法斯特CGI 而非 CGI 左券
    • CGI 与 FastCGI 架构
    • 再看 FastCGI 协议
    • Web 服务器和 法斯特CGI 交互进度
    • 为何需求在信息头发送 RequestID 这么些标记?
  • PHP-FPM

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 9003

char* 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 OKrnContent-Type:text/htmlrnContent-Length: %drnServer: mengkangrnrn%s";

    sprintf(res,html_response_template,strlen(buf),buf);

    return res;
}

介绍

在用PHP开荒的历程中,大家日常使用Nginx或许Apache作为大家的Web服务器。不过PHP是什么样与这几个Web服务器通信的吗?

  • Apache把PHP作为三个模块集成到Apache进度运行,这种mod_php的运作形式与PHP-CGI未有其他涉及。

  • Nginx是通过FastCGI来促成与PHP的通讯。

要谈法斯特CGI就务须先说说CGI。那怎么是CGI?

CGI(Common Gateway Interface:通用网关接口卡塔尔(قطر‎是Web 服务器运转时外界程序的规范,按CGI 编写的次第能够扩张服务器成效。CGI 应用程序能与浏览器举行相互,还可由此数据库API 与数据库服务器等外界数据源进行通讯,从数据库服务器中获取数据。--百度百科

CGI协议同 HTTP 左券同样是一个「应用层」左券,它的 作用 是为了减轻 Web 服务器与 PHP 应用(或其余 Web 应用)之间的通讯难点。

既是它是多少个「左券」,换言之它与语言非亲非故,即只要是贯彻类 CGI 合同的行使就能够达成相互作用的通讯。

如上代码中的重视:

  • 66~81行找到CGI程序的相对路线(我们为了轻巧,直接将其根目录定义为Web程序的当前目录),那样就足以在子进程中实践CGI 程序了;同时安装境遇变量,方便CGI程序运转时读取;
  • 94~95行将 CGI 程序的正经输出结果写入 Web 服务器守护进度的缓存中;
  • 97行则将包装后的 html 结果写入顾客端 socket 描述符,重返给连接Web服务器的客商端。

深入CGI协议

笔者们早就精通了 CGI 合同是为了做到 Web 服务器和选拔之间开展多少通讯那么些难点。那么,那生机勃勃节大家就来探问到底它们之间是怎样进展通讯的。

简简单单来说 CGI 公约它描述了 Web 服务器和应用程序之间举办数量传输的格式,何况只要大家的编制程序语言帮助标准输入、规范输出以致情况变量等拍卖,你就能够利用它来编排叁个CGI 程序。

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程序的同级目录。

代码中的第28行,从境况变量中读取前面在Web服务器守护进度中装置的情况变量,是大家演示的最重要。

CGI的周转规律

  • 当客商访谈大家的 Web 应用时,会发起叁个 HTTP 央求。最终 Web 服务器收到到那几个央求。

  • Web 服务器创立贰个新的 CGI 进度。在这里个历程中,将 HTTP 央浼数据已没有什么可争辨的格式深入深入分析出来,并透过专门的学问输入和情状变量传入到 UGL450L 钦定的 CGI 程序(PHP 应用 $_SERVER)。

  • Web 应用程序管理完毕后将再次来到数据写入到正规输出中,Web 服务器进度则从正式输出流中读取到响应,并利用 HTTP 合同再次回到给客户响应。

一句话正是 Web 服务器中的 CGI 进度将收取到的 HTTP 必要数据读取到情状变量中,通过正规输入转载给 PHP 的 CGI 程序;当 PHP 程序处理实现后,Web 服务器中的 CGI 进程从业内输出中读取再次来到数据,并改造回 HTTP 响应信息格式,最终将页面呈献给客商。然后 Web 服务器关闭掉那些 CGI 进度。

能够说 CGI 左券极其长于管理 Web 服务器和 Web 应用的通讯难点。但是,它有一个严重破绽,对于各类诉求都急需重新 fork 出三个 CGI 进度,管理到位后立马关闭。

法斯特CGI 工作规律剖判

对峙于 CGI/1.1 标准在 Web 服务器在地点 fork 八个子进度实践 CGI 程序,填充 CGI 预约义的处境变量,放入系统情状变量,把 HTTP body 体的 content 通过专门的工作输入传入子进度,管理达成之后经过正规输出重返给 Web 服务器。法斯特CGI 的中央则是禁止守旧的 fork-and-execute 方式,减少每一回运维的伟大费用(前面以 PHP 为例表明),以常驻的主意来拍卖央求。

法斯特CGI 职业流程如下:

  1. 法斯特CGI 进度微型机自己伊始化,运转四个 CGI 解释器进度,并听候来自 Web Server 的接连几日。
  2. Web 服务器与 法斯特CGI 进度微处理机实行 Socket 通讯,通过 法斯特CGI 磋商发送 CGI 情形变量和标准输入数据给 CGI 解释器进度。
  3. CGI 解释器进度达成管理后将行业内部输出和错误新闻从同一而再一而再接重回 Web Server。
  4. CGI 解释器进程接着等待并管理来自 Web Server 的下八个三番若干次。

百家了乐八大技巧 2

法斯特CGI 与守旧 CGI 格局的界别之一则是 Web 服务器不是直接推行 CGI 程序了,而是经过 socket 与 法斯特CGI 响应器(法斯特CGI 进度微处理机)实行相互,Web 服务器须求将 CGI 接口数据封装在根据 法斯特CGI 左券包中发送给 FastCGI 响应器程序。正是出于 法斯特CGI 进程微处理器是依照socket 通讯的,所以也是分布式的,Web服务器和CGI响应器服务器分开计划。

再啰嗦一句,法斯特CGI 是意气风发种左券,它是树立在CGI/1.1根底之上的,把CGI/1.1里面包车型大巴要传送的多少经过FastCGI合同定义的顺序、格式实行传递。

CGI研讨的弱项

  • 历次管理顾客哀告,都必要重新 fork CGI 子进度、销毁 CGI 子进度。

  • 一琳琅满指标 I/O 开支减弱了网络的吞吐量,产生了财富的荒废,在大并发时会时有发生严重的品质难点。

预备干活

可能上面的从头到尾的经过明白起来依旧很空虚,那是出于第大器晚成对法斯特CGI协议还向来不叁个概况的认知,第二还未实际代码的求学。所以须求事情未发生前学习下 法斯特CGI 左券的内容,不自然须要完全看懂,可大概理解之后,看完本篇再组成着读书驾驭消食。

http://www.fastcgi.com/devkit… (克罗地亚语原版)
http://andylin02.iteye.com/bl… (中文版)

深入FastCGI协议

从功能上来说,CGI 公约已经完全能够解决 Web 服务器与 Web 应用之间的数据通讯难点。但是由于各种央浼都亟待再行 fork 出 CGI 子进度引致品质堪忧,所以依据 CGI 公约的底子上做了改善便有了 FastCGI 公约,它是生机勃勃种常驻型的 CGI 公约。

实为上来将 法斯特CGI 和 CGI 合同大约全盘相仿,它们都足以从 Web 服务器里接收到均等的多寡,分化之处在于采取了差异的通讯方式。

再来回想一下 CGI 协议每趟接到到 HTTP 诉求时,都亟需涉世 fork 出 CGI 子进度、施行拍卖并销毁 CGI 子进度那黄金年代多元职业。

FastCGI 公约使用 经过间通讯 来管理客商的央浼,上面大家就来看看它的周转原理。

法斯特CGI 协议解析

下边结合 PHP 的 法斯特CGI 的代码进行解析,不作特殊表达以下代码均来自于 PHP 源码。

法斯特CGI公约运行规律

  • 法斯特CGI 进度微处理机运营时会创设二个 主 进度和多个 CGI 解释器进度(Worker 进度),然后等待 Web 服务器的接连。

  • Web 服务器收到 HTTP 央浼后,将 CGI 报文通过 套接字(UNIX 或 TCP Socket)举办通讯,将意况变量和伸手数据写入标准输入,转载到 CGI 解释器进度。

  • CGI 解释器进度达成管理后将业内输出和错误信息从同三回九转接再次回到给 Web 服务器。

  • CGI 解释器进程等待下三个 HTTP 诉求的到来。

法斯特CGI 新闻类型

法斯特CGI 将传输的音讯做了大多项目标划分,其组织体定义如下:

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;

何以是 法斯特CGI 而非 CGI 公约

意气风发经单纯因为做事方式的不如,就如并从未什么样大不断的。并没到非要选拔法斯特CGI 合同不可的境地。

可是,对于那几个就疑似渺小的异样,但意义出色,最后的结果是促成出来的 Web 应用构造上的差别。

消息的出殡顺序

下图是二个轻便的新闻传递流程

百家了乐八大技巧 3

最头阵送的是FCGI_BEGIN_REQUEST,然后是FCGI_PARAMSFCGI_STDIN,由于每一种音讯头(上边将详细说明)里面能够世襲的最大尺寸是65535,所以那二种档期的顺序的消息不自然只发送三遍,有异常的大或许总是发送数次。

FastCGI 响应体管理完结之后,将发送FCGI_STDOUTFCGI_STDERR,同理也说不允许数十三次总是发送。最后以FCGI_END_REQUEST代表诉求的终结。

内需专心的有些,FCGI_BEGIN_REQUESTFCGI_END_REQUEST分级标记着伸手的初始和竣事,与成套左券城门失火,所以他们的音信体的剧情也是说道的风流罗曼蒂克有的,因而也许有对应的布局体与之对应(前面会详细表达)。而遭遇变量、标准输入、典型输出、错误输出,这一个都以事情相关,与协商非亲非故,所以她们的新闻体的内容则无构造体对应。

由于一切新闻是二进制接二连三传递的,所以必须定义三个联合的组织的信息头,那样以便读取每种音信的新闻体,方便音讯的切割。那在网络通信中是特别遍布的意气风发种手腕。

CGI 与 FastCGI 架构

在 CGI 讨论中,Web 应用的生命周期完全依附于 HTTP 需要的注脚周期。

对每一种选拔到的 HTTP 哀告,都急需重启二个 CGI 进度来实行管理,管理到位后必需关闭 CGI 进度,技巧达到通告 Web 服务器此番HTTP 乞请管理完了的目标。

但是在 法斯特CGI 中完全不一样。

法斯特CGI 进度是常驻型的,生机勃勃旦运行就能够拍卖全体的 HTTP 须求,而没有必要直接退出。

FastCGI 消息头

如上,法斯特CGI 音讯分10种新闻类型,有的是输入过多输出。而具有的音讯都是一个新闻头起头。其构造体定义如下:

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标记法斯特CGI合同版本。
  • type 标识法斯特CGI记录类型,相当于记录推行的貌似意义。
  • requestId标志记录所属的法斯特CGI乞请。
  • contentLength笔录的contentData组件的字节数。

至于地点的xxB1xxB0的说道表达:当多少个相邻的结构组件除了后缀“B1”和“B0”之外命名相符期,它表示那八个构件可就是估价为B1<<8 + B0的单个数字。该单个数字的名字是这么些构件减去后缀的名字。那个约定归咎了一个由超过多个字节表示的数字的处理格局。

比如合同头中requestIdcontentLength意味着的最大值就是65535

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>

int main()
{
   unsigned char requestIdB1 = UCHAR_MAX;
   unsigned char requestIdB0 = UCHAR_MAX;
   printf("%dn", (requestIdB1 << 8) + requestIdB0); // 65535
}

您大概会想到假使叁个音讯体长度抢先65535怎么做,则分割为多少个相似等级次序的音讯发送就能够。

再看 FastCGI 协议

经过前边的教学,我们相比较已经能够很正确的说出来 法斯特CGI 是大器晚成种通讯协议 这样的结论。今后,大家就将关注的要害挪到协和本人,来会见这几个公约的定义。

同 HTTP 公约相符,FastCGI 合同也会有音讯头和音讯体组成。

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_BEGIN_REQUEST中的flags组件包括多个决定线路关闭的位:flags & FCGI_KEEP_CONN:如若为0,则选用在对此番须求响应后关门线路。假诺非0,应用在对本次恳求响应后不会倒闭线路;Web服务器为线路保持响应性。

音信头音信

第大器晚成的消息头音讯如下:

  • Version: 用于表示 法斯特CGI 左券版本号。

  • Type: 用于标志 法斯特CGI 新闻的类型 - 用于钦赐管理那一个音信的主意。

  • RequestID: 标记出最近所属的 法斯特CGI 央浼。

  • Content Length: 数据手提袋体所占字节数。

上一篇:没有了 下一篇:没有了