您的位置:365bet手机在线 > Web前端 > 365bet线上手机投注协议的运行原理,协议以及在

365bet线上手机投注协议的运行原理,协议以及在

发布时间:2020-01-16 22:31编辑:Web前端浏览(166)

    在商量 法斯特CGI 此前,必须要说古板的 CGI 的干活原理,同期应当大概了然 CGI 1.1 协议

    目录

    价值观 CGI 职业原通晓析

    客商端访问有些 UENVISIONL 地址然后,通过 GET/POST/PUT 等形式交给数据,并透过 HTTP 合同向 Web 服务器发出乞求,服务器端的 HTTP Daemon(守护进程)将 HTTP 诉求里描述的新闻透过标准输入 stdin 和意况变量(environment variable卡塔尔国传递给主页钦赐的 CGI 程序,并运营此应用程序进行拍卖(饱含对数据库的拍卖),管理结果通过正规输出 stdout 重临给 HTTP Daemon 守护进度,再由 HTTP Daemon 进度经过 HTTP 左券重返给客户端。

    下面的这段话精通恐怕如故相比空虚,上边我们就由此贰回GET央浼为例进行详细表明。

    365bet线上手机投注 1

    上面用代码来促成图中宣布的法力。Web 服务器运维四个 socket 监听服务,然后在当地实施 CGI 程序。前面有比较详细的代码解读。

    • 介绍
    • 深入CGI协议
      • CGI的周转原理
      • CGI共同商议的后天不良
    • 深入FastCGI协议
      • FastCGI合同运转原理
      • 干什么是 法斯特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的通讯。

    要谈FastCGI就务须先说说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 须要数据已毫无疑问格式解析出来,并经过专门的学问输入和遭受变量传入到 UTiggoL 钦命的 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 服务器。FastCGI 的基本则是不许古板的 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 的下贰个连接。

    365bet线上手机投注 2

    法斯特CGI 与观念 CGI 形式的区分之一则是 Web 服务器不是一贯推行 CGI 程序了,而是通过 socket 与 法斯特CGI 响应器(法斯特CGI 进度管理器)进行互相,Web 服务器供给将 CGI 接口数据封装在安分守纪 法斯特CGI 左券包中发送给 法斯特CGI 响应器程序。正是出于 法斯特CGI 进程微处理机是基于 socket 通讯的,所以也是遍及式的,Web服务器和CGI响应器服务器分开安排。

    再啰嗦一句,法斯特CGI 是生机勃勃种契约,它是创造在CGI/1.1根基之上的,把CGI/1.1里边的要传递的数目经过法斯特CGI公约定义的相继、格式举办传递。

    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 的 FastCGI 的代码进行剖析,不作特殊表明以下代码均源于于 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 应用布局上的异样。

    音信的出殡顺序

    下图是叁个简便的音信传递流程

    365bet线上手机投注 3

    第一发送的是FCGI_BEGIN_REQUEST,然后是FCGI_PARAMSFCGI_STDIN,由于各样音讯头(上面将详细表达)里面能够承继的最大尺寸是65535,所以这两种类型的消息不自然只发送三次,有希望总是发送数次。

    法斯特CGI 响应体管理达成之后,将发送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 公约相近,法斯特CGI 公约也可以有音讯头和音讯体组成。

    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: 数据托特包体所占字节数。

    本文由365bet手机在线发布于Web前端,转载请注明出处:365bet线上手机投注协议的运行原理,协议以及在

    关键词: