15.FastCGI

这里写图片描述
这里写图片描述
这里写图片描述

#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 /cgi-bin/user?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);             // /cgi-bin/user?id=1 
        filename = strtok(p, "?");           // /cgi-bin/user

        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 OK\r\nContent-Type:text/html\r\nContent-Length: %d\r\nServer: mengkang\r\n\r\n%s";

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

    return res;
}

这里写图片描述

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

这里写图片描述
这里写图片描述
这里写图片描述

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;

这里写图片描述

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

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

这里写图片描述
这里写图片描述

FCGI_REQUEST_COMPLETE:请求的正常结束。
FCGI_CANT_MPX_CONN:拒绝新请求。这发生在Web服务器通过一条线路向应用发送并发的请求时,后者被设计为每条线路每次处理一个请求。
FCGI_OVERLOADED:拒绝新请求。这发生在应用用完某些资源时,例如数据库连接。
FCGI_UNKNOWN_ROLE:拒绝新请求。这发生在Web服务器指定了一个应用不能识别的角色时。

这里写图片描述

{FCGI_BEGIN_REQUEST,   1, {FCGI_RESPONDER, 0}}
{FCGI_PARAMS,          1, "\013\002SERVER_PORT80\013\016SERVER_ADDR199.170.183.42 ... "}
{FCGI_STDIN,           1, "quantity=100&item=3047936"}
{FCGI_STDOUT,          1, "Content-type: text/html\r\n\r\n<html>\n<head> ... "}
{FCGI_END_REQUEST,     1, {0, FCGI_REQUEST_COMPLETE}}

这里写图片描述
这里写图片描述
这里写图片描述

  while (parent) {
        do {
            pid = fork();   //  生成新的子进程
            switch (pid) {
            case 0: //  子进程
                parent = 0;

                /* don't catch our signals */
                sigaction(SIGTERM, &old_term, 0);   //  终止信号
                sigaction(SIGQUIT, &old_quit, 0);   //  终端退出符
                sigaction(SIGINT,  &old_int,  0);   //  终端中断符
                break;
                ...
                default:
                /* Fine */
                running++;
                break;
        } while (parent && (running < children));

    ...
        while (!fastcgi || fcgi_accept_request(&request) >= 0) {
        SG(server_context) = (void *) &request;
        init_request_info(TSRMLS_C);
        CG(interactive) = 0;
                    ...
            }

这里写图片描述
这里写图片描述
这里写图片描述

/* {{{ sapi_module_struct cgi_sapi_module
 */
static sapi_module_struct cgi_sapi_module = {
"cgi-fcgi",                     /* name */
"CGI/FastCGI",                  /* pretty name */

php_cgi_startup,                /* startup */
php_module_shutdown_wrapper,    /* shutdown */

sapi_cgi_activate,              /* activate */
sapi_cgi_deactivate,            /* deactivate */

sapi_cgibin_ub_write,           /* unbuffered write */
sapi_cgibin_flush,              /* flush */
NULL,                           /* get uid */
sapi_cgibin_getenv,             /* getenv */

php_error,                      /* error handler */

NULL,                           /* header handler */
sapi_cgi_send_headers,          /* send headers handler */
NULL,                           /* send header handler */

sapi_cgi_read_post,             /* read POST data */
sapi_cgi_read_cookies,          /* read Cookies */

sapi_cgi_register_variables,    /* register server variables */
sapi_cgi_log_message,           /* Log message */
NULL,                           /* Get request time */
NULL,                           /* Child terminate */

STANDARD_SAPI_MODULE_PROPERTIES
};
/* }}} */

这里写图片描述
http://www.fastcgi.com/drupal/node/2
http://baike.baidu.com/view/641394.htm


http://www.php-internals.com/book/?p=chapt02/02-02-03-fastcgi

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值