为什么需要CGI

最早的Web服务器简单地响应浏览器发来的HTTP请求,并将存储在服务器上的HTML文件返回给浏览器,也就是静态html。事物总是不 断发展,网站也越来越复杂,所以出现动态技术。但是服务器并不能直接运行 php,asp这样的文件,自己不能做,外包给别人吧,但是要与第三做个约定,我给你什么,然后你给我什么,就是我把请求参数发送给你,然后我接收你的处理结果给客户端。那这个约定就是 common gateway interface,简称cgi。这个协议可以用vb,c,php,python 来实现。

WEB服务器与CGI程序交互

WEB服务器将根据CGI程序的类型决定数据向CGI程序的传送方式,一般来讲是通过标准输入/输出流和环境变量来与CGI程序间传递数据。

CGI程序通过标准输入(STDIN)和标准输出(STDOUT)来进行输入输出。此外CGI程序还通过环境变量来得到输入,操作系统提供了许 多环境变量,它们定义了程序的执行环境,应用程序可以存取它们。Web服务器和CGI接口又另外设置了一些环境变量,用来向CGI程序传递一些重要的参 数。HTTP协议的GET方法通过环境变量QUERY-STRING向CGI程序传递Form中的数据。每个CGI程序只能处理一个用户请求,所以在激活一个CGI程序进程时也创建了属于该进程的环境变量。CGI程序在处理完一个请求后就退出,在下一个请求到来时再创建一个新进程执行CGI程序。

下面是一些常用的CGI环境变量:

FastCGI

CGI工作原理:每当客户请求CGI的时候,WEB服务器就请求操作系统生成一个新的CGI解释器进程(如php-cgi.exe),CGI 的一个进程则处理完一个请求后退出,下一个请求来时再创建新进程。当然,这样在访问量很少没有并发的情况也行。可是当访问量增大,并发存在,这种方式就不 适合了。于是就有了fastcgi。FastCGI像是一个常驻(long-live)型的CGI,它可以一直执行着,只要激活后,不会每次都要花费时间去fork一次(这是CGI最为人诟病的fork-and-execute 模式)。
一般情况下,FastCGI的整个工作流程是这样的:

  1. Web Server启动时载入FastCGI进程管理器(IIS ISAPI或Apache Module)
  2. FastCGI进程管理器自身初始化,启动多个CGI解释器进程(可见多个php-cgi)并等待来自Web Server的连接。
  3. 当客户端请求到达Web Server时,FastCGI进程管理器选择并连接到一个CGI解释器。 Web server将CGI环境变量和标准输入发送到FastCGI子进程php-cgi。
  4. FastCGI 子进程完成处理后将标准输出和错误信息从同一连接返回Web Server。当FastCGI子进程关闭连接时, 请求便告处理完成。FastCGI子进程接着等待并处理来自FastCGI进程管理器(运行在Web Server中)的下一个连接。 在CGI模式中,php-cgi在此便退出了。

PHP-FPM与Spawn-FCGI
  Spawn-FCGI是一个通用的FastCGI管理服务器,它是lighttpd中的一部份,很多人都用Lighttpd的Spawn-FCGI进行FastCGI模式下的管理工作。 但是有缺点,于是PHP-fpm就是针对于PHP的,Fastcgi的一种实现,他负责管理一个进程池,来处理来自Web服务器的请求。目前,PHP-fpm是内置于PHP的。

使用C++实现CGI

安装Apache服务器,将C++实现的CGI程序编译的可执行文件复制到Apache的cgi-bin目录下。

#include <iostream>
using namespace std;
int main (){cout << "Content-type:text/html\r\n\r\n";cout << "<html>\n";cout << "<head>\n";cout << "<title>Hello World - First CGI Program</title>\n";cout << "</head>\n";cout << "<body>\n";cout << "<h2>Hello World! This is my first CGI program</h2>\n";cout << "</body>\n";cout << "</html>\n";   return 0;
}

上述程序手动执行效果:

在浏览器中输入"http://42.96.142.129:8083/cgi-bin/test",浏览器输出内容:

获取CGI的环境变量

#include <iostream>
#include <stdlib.h>
using namespace std;
const string ENV[24] = {
"COMSPEC", "DOCUMENT_ROOT", "GATEWAY_INTERFACE", "HTTP_ACCEPT", "HTTP_ACCEPT_ENCODING","HTTP_ACCEPT_LANGUAGE", "HTTP_CONNECTION", "HTTP_HOST", "HTTP_USER_AGENT", "PATH", "QUERY_STRING", "REMOTE_ADDR", "REMOTE_PORT","REQUEST_METHOD", "REQUEST_URI", "SCRIPT_FILENAME","SCRIPT_NAME", "SERVER_ADDR", "SERVER_ADMIN","SERVER_NAME","SERVER_PORT","SERVER_PROTOCOL","SERVER_SIGNATURE","SERVER_SOFTWARE"};  int main(){cout<<"Content-type:text/html\r\n\r\n";cout<<"<html>\n";cout<<"<head>\n";cout<<"<title>CGI Envrionment Variables</title>\n";cout<<"</head>\n";cout<<"<body>\n";cout<<"<table border=\"0\"cellspacing=\"2\">";for(int i=0;i<24;i++){cout<<"<tr><td>"<<ENV[i]<<"</td><td>";char *value = getenv(ENV[i].c_str()); if(value!= 0){cout << value;}else{cout<<"Environment variable does not exist.";}cout<<"</td></tr>\n";}cout<<"</table><\n";cout<<"</body>\n";cout<<"</html>\n"; return 0;
}

GET参数的获取

在GET方法下,CGI程序无法直接从服务器的标准输入中获取数据,服务器把它从http协议接收到的数据编码到环境变量QUERY_STRING(或PATH_INFO)。采用GET方法时,只需把这些数据附加到URL的末尾,如http://42.96.142.129:8083/cgi-bin/1023?a=1&b=2&c=3,这时候QUERY_STRING的值为a=1&b=2&c=3。

#include<iostream>
#include<stdlib.h>
#include<vector>
#include<string>
using namespace std;
vector<string> StringSplit(const string& sData, const string& sDelim){vector<string>vItems;vItems.clear();string::size_type bpos = 0;string::size_type epos = 0;string::size_type nlen = sDelim.size();while ((epos=sData.find(sDelim, epos)) != string::npos){vItems.push_back(sData.substr(bpos, epos-bpos));epos += nlen;bpos = epos;}vItems.push_back(sData.substr(bpos, sData.size()-bpos));return vItems;
}
int main(){cout << "Content-type:text/html\r\n\r\n";cout << "<html>\n";cout << "<head>\n";cout << "<title>Hello World - First CGI Program</title>\n";cout << "</head>\n";cout << "<body>\n"; cout<<"get parameter:<br/>";char *value = getenv("QUERY_STRING");  if(value!= 0){/*"a=1&b=2&c=3"*/vector<string>paras=StringSplit((const string)value,"&");vector<string>::iterator iter=paras.begin();for(;iter!=paras.end();iter++){vector<string>singlepara=StringSplit(*iter,"=");cout<<singlepara[0]<<" "<<singlepara[1]<<"<br/>";}cout << "</body>\n";cout << "</html>\n";   return 0;
}

POST参数的获取

在POST方法下,CGI程序可以直接从服务器的标准输入中获取数据,不过要先从CONTENT_LENGTH这个环境变量中得到POST参数的长度,然后再读取相应长度的内容。
post.html代码

<html>
<head>
<title>CGI Post</title>
</head>
<body>
<tr><td>
<div style="font-weight:bold; font-size:15px">Method: POST</div>
<div>lease input two number:<div>
<form method="post" action="./cgi-bin/post">
<input type="txt" size="3" name="m">*
<input type="txt" size="3" name="n">=
<input type="submit" value="result">
</form>
</td></tr>
</table>
</body>
</html>

将post.html复制到htdocs目录下

#include<iostream>
#include<stdlib.h>
#include<stdio.h>
using namespace std;
int main(){cout << "Content-type:text/html\r\n\r\n";cout << "<html>\n";cout << "<head>\n";cout << "<title>Testing Post</title>\n";cout << "</head>\n";cout << "<body>\n"; char *lenstr =getenv("CONTENT_LENGTH");if(lenstr==NULL){cout<<"Error, CONTENT_LENGTH should be entered!"<<"<br/>";}else{int len=atoi(lenstr);char poststr[20];fgets(poststr,len+1,stdin);cout<<"poststr:"<<poststr<<"<br/>"; char m[10],n[10];if(sscanf(poststr,"m=%[^&]&n=%s",m,n)!=2){cout<<"Error: Parameters are not right!<br/>";}else{cout<<"m * n = "<<atoi(m)*atoi(n)<<"<br/>";}}cout << "</body>\n";cout << "</html>\n";   return 0;
}


在浏览器中输入"http://42.96.142.129:8083/post.html",在输入框中分别输入3和4,点击result按钮,输出如上图所示的结果。

使用PHP实现CGI的情况

记得曾在xp 配置 apache + php ,会在apache 配置下面一段:

LoadModule php5_module C:/php/php5apache2_2.dll

当PHP需要在Apache服务器下运行时,一般来说,它可以模块的形式集成, 此时模块的作用是接收Apache传递过来的PHP文件请求,并处理这些请求, 然后将处理后的结果返回给Apache。如果我们在Apache启动前在其配置文件中配置好了PHP模块, PHP模块通过注册apache2的ap_hook_post_config挂钩,在Apache启动的时候启动此模块以接受PHP文件的请求。
Apache 的Hook机制是指:Apache 允许模块(包括内部模块和外部模块,例如mod_php5.so,mod_perl.so等)将自定义的函数注入到请求处理循环中。 换句话说,模块可以在Apache的任何一个处理阶段中挂接(Hook)上自己的处理函数,从而参与Apache的请求处理过程。 mod_php5.so/ php5apache2.dll就是将所包含的自定义函数,通过Hook机制注入到Apache中,在Apache处理流程的各个阶段负责处理php请 求。

仿真使用STDOUT和STDIN与Web server交互

close(STDOUT_FILENO);
dup(connfd);  //connfd是sockert句柄
printf("abcd\n");
close(connfd);

先关闭标准输出文件描述符STDOUT_FILENO(其值是1)。使用dup复制socket文件描述符connfd。因为dup总返回系统中最小的可用文件描述符,所以返回值实际是1,即之前关闭的标准输出文件描述符的值。这样服务器输出到标准输出的内容就会直接发送到与客户连接对应的socket上。

参考:
https://www.cnblogs.com/wanghetao/p/3934350.html

CGI入门一:使用C++实现CGI程序相关推荐

  1. CGI简介用C来写CGI程序简要指南

    1. 什么是CGI? CGI 是通用网关接口(Common Gateway Interface)的缩写. 它主要用于服务器端动态输出客户端的请求(如,HTML页面/二进制文件). 也就是说客户端请求参 ...

  2. CGI简介——用C来写CGI程序简要指南

    http://www.cnblogs.com/ribavnu/archive/2012/11/18/2775552.html 1. 什么是CGI ? CGI 是通用网关接口(Common Gatewa ...

  3. C/S和B/S模式的主要特点以及区别在那里?画出CGI工作原理图,具体描述CGI的主要流程和实现步骤。

    C/S和B/S模式的主要特点以及区别在那里? CS即Client/Server(客户机/服务器)结构. C/S结构在技术上很成熟,它的主要特点是交互性强.具有安全的存取模式.网络通信量低.响应速度快. ...

  4. boa 调用 cgi 读取文件_PHP7的内核CGI与FastCGI,你懂多少?

    CGI:是 Web Server 与 Web Application 之间数据交换的一种协议. FastCGI:同 CGI,是一种通信协议,但比 CGI 在效率上做了一些优化. PHP-CGI:是 P ...

  5. ADO.NET Entity Framework 入门示例向导(附Demo程序下载)

    ADO.NET Entity Framework 入门示例向导(附Demo程序下载) ADO.NET Entity Framework 是.Net Framework 3.5 SP1 引入的实体框架, ...

  6. WinAPI入门: 第一个标准Win32窗口程序 [改进详细注释版]

    WinAPI入门: 第一个标准Win32窗口程序 下载链接: 若想立即看到本程序的运行结果,可点击EXE文件的免费下载链接; HelloWin_v1.sfx.exe;–带语音和背景音乐; 相关链接: ...

  7. 关于apache上的CGI文件问题总结--为什么无法找到cgi文件、为什么找到了cgi文件却不执行反而询问是否下载或直接显示文件代码

    最近我在研究web.cgi,比较好奇cgi这玩意,就在Ubuntu上下载安装了Apache(2.2版本),并写个简单的html文件 test.html 和相关的cgi文件 t.cgi. Apache的 ...

  8. 【部署教程入门级别】开源会议室小程序部署

    文章目录 前言 一.项目整体 二.前要准备 1.安装Python 开发环境 2.安装redis非关系数据库 3.安装mysql服务器和客户端 4.安装git工具 5.安装微信开发工具 6.Github ...

  9. c语言入门经典必背18个程序,c语言入门经典必背18个程序

    c语言入门经典必背18个程序 1 . /* 输出 9*9 口诀.共 9 行 9 列, i 控制行, j 控制列. */ #include "stdio.h" main() {int ...

  10. 网络知识入门,Web服务器的CGI程序,浏览器如何判断响应内容:文本,图片还是音频文件?(十九)

    目录 将请求的uri转换为实际的文件名 运行CGI程序 web服务器的访问控制 浏览器接受响应并返回内容 浏览器接受响应消息后如何显示内容 浏览器显示网页内容:访问完成 将请求的uri转换为实际的文件 ...

最新文章

  1. 2021年大数据Flink(十五):流批一体API Connectors ​​​​​​​Kafka
  2. Java集合框架综述,这篇让你吃透!
  3. 深度学习——02、深度学习入门——卷积神经网络
  4. Telnet和FTP
  5. css-modules,可视化介绍CSS Modules是什么?
  6. z平面与s平面计算机控制稳定性,2 计算机控制系统分析
  7. Java程序员们最常犯的10个错误
  8. hdu 5735 Born Slippy 暴力
  9. 昆仑通态触摸屏保存历史曲线_昆仑通态历史曲线如何组态呢?
  10. 网站访问统计分析工具之罗列比较
  11. 手机恢复出厂设置命令_OpenWRT 恢复出厂设置命令
  12. 【2022研电赛】安谋科技企业命题一等奖:基于EAIDK-610的中国象棋机器人对弈系统
  13. this java 错误_java异常错误处理
  14. Android系统移植与调试之-------build.prop文件详细赏析
  15. 京东 PC 首页 2019 改版前端总结
  16. 马来西亚之旅——吉隆坡、马六甲、槟城和亚庇攻略
  17. phpcms富文本框上传图片去除水印
  18. 怎样补充nmn,nmn胶囊正确服用方法,现在知道还不晚
  19. 循迹智能车红外模块的选取
  20. 8.NP交换部分内容汇总及VLAN

热门文章

  1. xxampp 配置php_MAC下使用XMAPP配置php环境
  2. 协同系统php,php然之协同管理系统
  3. iOS UITextView字数限制 拼音
  4. java wmic_Windows WMIC命令使用详解(附实例)
  5. 网页媒体播放利器 - JW Player使用心得
  6. jwplayer播放器初探
  7. ad中按钮开关的符号_收藏:电路图形符号大全
  8. Oracle 锁表查询及解锁
  9. 放大电路、单管共发射极放大电路结构、工作原理、lceda仿真
  10. CardView的基本使用、DrawerLayout 滑动菜单、Fragment