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[], web_result[];
int len;
FILE *cin; if ((lfd = socket(AF_INET, SOCK_STREAM, )) == -) {
perror("create socket failed");
exit();
} memset(&serv_addr, , 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)) == -) {
perror("bind error");
exit();
} if (listen(lfd, ) == -) {
perror("listen error");
exit();
} signal(SIGCLD, SIG_IGN); while () {
clin_len = sizeof(clin_addr);
if ((cfd = accept(lfd, (struct sockaddr *) &clin_addr, &clin_len)) == -) {
perror("接收错误\n");
continue;
} cin = fdopen(cfd, "r");
setbuf(cin, (char *) );
fgets(buf, , 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); // /user?id=1
filename = strtok(p, "?"); // /user if (strcmp(filename, "/favicon.ico") == ) {
continue;
} query_string = strtok(NULL, "?"); // id=1
putenv(str_join(query_string_pre, query_string)); //============================ cgi 环境变量设置演示 ============================ int pid = fork(); if (pid > ) {
close(cfd);
}
else if (pid == ) {
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();
}
else {
perror("fork error");
exit();
}
} close(lfd); return ;
} char *str_join(char *str1, char *str2) {
char *result = malloc(strlen(str1) + strlen(str2) + );
if (result == NULL) exit();
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;
}

user.c

#include <stdio.h>
#include <stdlib.h> // 通过获取的 id 查询用户的信息
int main(void) { //============================ 模拟数据库 ============================
typedef struct {
int id;
char *username;
int age;
} user; user users[] = {
{},
{
,
"taoshihan", }
};
//============================ 模拟数据库 ============================ char *query_string;
int id; query_string = getenv("QUERY_STRING"); if (query_string == NULL) {
printf("没有输入数据");
} else if (sscanf(query_string, "id=%d", &id) != ) {
printf("没有输入id");
} else {
printf("用户信息查询<br>学号: %d<br>姓名: %s<br>年龄: %d", id, users[id].username, users[id].age);
} return ;
}

访问文件流(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\n",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)

[PHP] 通用网关接口CGI 的运行原理的更多相关文章

  1. (一)CGI (通用网关接口) 简介

    CGI (通用网关接口)公共网关接口(Common Gateway Interface,CGI)是Web 服务器运行时外部程序的规范,按CGI 编写的程序可以扩展服务器功能.CGI 应用程序能与浏览器 ...

  2. 【重要】python之模块CGI 通用网关接口

    # -*- coding: utf-8 -*- #python 27 #xiaodeng #CGI模块 import CGI #通用网关接口,它是一段程序,运行在服务器上如:HTTP服务器,提供同客户 ...

  3. CGI(Common Gateway Interface),通用网关接口

    通用网关接口,简称CGI,是一种根据请求信息动态产生回应内容的技术.通过CGI,Web 服务器可以将根据请求不同启动不同的外部程序,并将请求内容转发给该程序,在程序执行结束后,将执行结果作为回应返回给 ...

  4. CGI (通用网关接口)

    CGI cgi即 Common Gateway Interface 译作 通用网关接口 是应用程序与应用程序之间的输入输出协议.比如我们写信,规定了开头一句写称呼,中间写内容,最后署名和日期.看到这种 ...

  5. 通用网关接口 ruby perl web页面 文本处理 脚本语言

    小结: 1.只要可以对标准输入输出进行操作,那么无论任何语言都可以编写CGI程序. <代码的未来> 在Ruby诞生的1993年,互联网还没有现在这样普及,因此Ruby也不是一开始就面向We ...

  6. CGI(通用网关接口)

    公共网关接口 CGI(Common Gateway Interface) 是WWW技术中最重要的技术之一,有着不可替代的重要地位.CGI是外部应用程序(CGI程序)与Web服务器之间的接口标准,是在C ...

  7. CGI 和 FastCGI 协议的运行原理

    目录 介绍 深入CGI协议 CGI的运行原理 CGI协议的缺陷 深入FastCGI协议 FastCGI协议运行原理 为什么是 FastCGI 而非 CGI 协议 CGI 与 FastCGI 架构 再看 ...

  8. 【转】CGI 和 FastCGI 协议的运行原理

    介绍 深入CGI协议 CGI的运行原理 CGI协议的缺陷 深入FastCGI协议 FastCGI协议运行原理 为什么是 FastCGI 而非 CGI 协议 CGI 与 FastCGI 架构 再看 Fa ...

  9. nginx + php-fpm 运行原理

    一.关于nginx 1.1 简单认知 我们都知道nginx 是web服务器. 也知道 用户访问时通过ip和端口访问 nginx. 那么nginx 是如何 通过php 获取数据并返回数据的呢? 1.2 ...

随机推荐

  1. Spring Boot启动过程(六):内嵌Tomcat中StandardHost、StandardContext和StandardWrapper的启动

    看代码有助于线上出现预料之外的事的时候,不至于心慌... StandardEngine[Tomcat].StandardHost[localhost]的启动与StandardEngine不在同一个线程 ...

  2. [CISCO] 交换机间链路聚合端口聚合

    [CISCO] 交换机间链路聚合端口聚合 一.Introduction 端口通道( port channel ) 是一种聚合多个物理接口 ( that ) 创建一个逻辑接口.你可以捆扎( bundle ...

  3. iOS学习笔记(6)——翻译苹果文档About Windows and Views

    About Windows and Views 关于窗口和视图 In iOS, you use windows and views to present your application’s cont ...

  4. Eclipse 的SVN 插件

    Eclipse 的SVN 插件 简介  Subversive Eclipse 团队开发的SVN 插件. Subclipse Apache 的SVN 团队开发的Eclipse 插件.   Subvers ...

  5. Echarts【1、数据过多导致显示不全分页,2、数据展示探讨分析】

    var len=<c:out value="${len }"></c:out>; var dataZoom_end=null; //为空默认100%所以默认 ...

  6. orcal创建序列

    CREATE SEQUENCE flowjobseq --序列名INCREMENT BY 1 -- 每次加几个 START WITH 2000 -- 从1开始计数 NOMAXVALUE -- 不设置最 ...

  7. 关于npm run dev报错npm ERR! missing script: dev

    出现这个问题应当重新使用 vue init webpack 来初始化工程. 在执行 npm run dev 就可以执行了.

  8. Visual Studio 2019 Key

    Visual Studio 2019 Enterprise:BF8Y8-GN2QH-T84XB-QVY3B-RC4DF Visual Studio 2019 Professional:NYWVH-HT ...

  9. POJ-1258 Agri-Net(最小生成树)

    Description Farmer John has been elected mayor of his town! One of his campaign promises was to brin ...

  10. 通过js获取内网ip和外网ip的简单方法 ...

    今天遇到了一个需求,需要获取用户当前的内网ip, 找了半天终于找到了方法,遂将找到的方法记录下来,留给需要的人. 1,获取内网ip function getIP(callback) { let rec ...