zoukankan      html  css  js  c++  java
  • [PHP] 通用网关接口CGI 的运行原理

    CGI 的运行原理:
    1.客户端访问某个 URL 地址之后,通过 GET/POST/PUT 等方式提交数据,并通过 HTTP 协议向 Web 服务器发出请求。
    2.服务器端的 HTTP Daemon(守护进程)启动一个子进程。然后在子进程中,将 HTTP 请求里描述的信息通过标准输入 stdin 和环境变量传递给 URL 指定的 CGI 程序,并启动此应用程序进行处理,处理结果通过标准输出 stdout 返回给 HTTP Daemon 子进程。
    再由 HTTP Daemon 子进程通过 HTTP 协议返回给客户端。

    #include <stdio.h>
    #include <stdlib.h>
    #include <signal.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("接收错误
    ");
                continue;
            }
     
            cin = fdopen(cfd, "r");
            setbuf(cin, (char *) 0);
            fgets(buf, 1024, cin); //读取第一行
            printf("
    %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);             // /user?id=1 
            filename = strtok(p, "?");           // /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
    Content-Type:text/html
    Content-Length: %d
    Server: mengkang
    
    %s";
     
        sprintf(res, html_response_template, strlen(buf), buf);
     
        return res;
    }

    user.c

    #include <stdio.h>
    #include <stdlib.h>
     
    // 通过获取的 id 查询用户的信息
    int main(void) {
     
        //============================ 模拟数据库 ============================
        typedef struct {
            int id;
            char *username;
            int age;
        } user;
     
        user users[] = {
                {},
                {
                        1,
                        "taoshihan",
                        10
                }
        };
        //============================ 模拟数据库 ============================
     
     
        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;
    }

    访问文件流(stream I/O)的方式进行网络数据传输
    1.fdopen:打开一个标准的IO流
    原型:FILE *fdopen(int fd, const char *type);
    fd是用open函数得到文件描述符,type是打开模式

    2.setbuf:定义流 stream 应如何缓冲
    原型:void setbuf(FILE *stream, char *buffer)

    3.fgets:从指定的流 stream 读取一行,并把它存储在 str 所指向的字符串内,如果成功,该函数返回相同的 str 参数。
    原型:char *fgets(char *str, int n, FILE *stream)

    处理并传递参数
    4.strtok:分解字符串 str 为一组字符串,delim 为分隔符。
    原型:char *strtok(char *str, const char *delim)

    5.putenv setenv getenv获取设置环境变量相关函数
    头文件:#include4<stdlib.h>
    putenv("PATH=/shihan");
    char *v=getenv("PATH");
    printf("%s ",v);

    拼接字符串
    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;
    }
    malloc:分配所需的内存空间,并返回一个指向它的指针。
    原型:void *malloc(size_t size)

    strcpy:把 src 所指向的字符串复制到 dest。
    原型:char *strcpy(char *dest, const char *src)

    strcat:把 src 所指向的字符串追加到 dest 所指向的字符串的结尾。
    char *strcat(char *dest, const char *src)

  • 相关阅读:
    androidimage: load large bitmap Efficiently
    display log information in terminal
    黑客人物介绍
    Linux 基础入门学习
    网络攻防 第四周学习总结
    网络攻防 第二周学习总结
    网络攻防 第三周学习总结
    SpringBoot入门Demo(Hello Word Boot)
    jquery的json对象与字符串之间转换
    Intellij IDEA导入web项目详解(解决访问的404)
  • 原文地址:https://www.cnblogs.com/taoshihan/p/8313418.html
Copyright © 2011-2022 走看看