简单说明CGI是什么
1. CGI是什么
CGI是common gateway interface的缩写,大家都译作通用网关接口,但很不幸,我们无法见名知意。
我们知道,web服务器所处理的内容都是静态的,要想处理动态内容,需要依赖于web应用程序,如php、jsp、python、perl等。但是web server如何将动态的请求传递给这些应用程序?它所依赖的就是cgi协议。没错,是协议,也就是web server和web应用程序交流时的规范。换句话说,通过cgi协议,再结合已搭建好的web应用程序,就可以让web server也能"处理"动态请求(或者说,当用户访问某个特定资源时,可以触发执行某个web应用程序来实现特定功能),你肯定知道处理两字为什么要加上双引号。
简单版的cgi工作方式如下:
例如,在谷歌搜索栏中搜索一个关键词"http",对应的URL为:
https://www.google.com/search?q=http&oq=http&aqs=chrome..69i57j69i60l4j0.1136j0j8&sourceid=chrome&ie=UTF-8
当谷歌的web server收到该请求后,先分析该url,从中知道了要执行search程序,并且还知道了一系列要传递给search的参数及其对应的value。web server会将这些程序参数和其它一些环境变量根据cgi协议通过TCP或套接字等方式传递给已启动的cgi程序(可能是cgi进程,或者是已加载的模块cgi模块)。当cgi进程接收到web server的请求后,调用search程序并执行,同时还会传递参数给search程序。search执行结束后,cgi进程/线程将处理结果返回给web server,web server再返回给浏览器。
有多种方式可以执行cgi程序,但对http的请求方法来说,只有get和post两种方法允许执行cgi脚本(即上面的search程序)。实际上post方法的内部本质还是get方法,只不过在发送http请求时,get和post方法对url中的参数处理方式不一样而已。
任何一种语言都能编写CGI,只不过有些语言比较擅长,有些语言则非常繁琐,例如用bash shell开发,那么需要用echo等打印语句将执行结果放在巨多无比的html的标签中输出给客户端。常用于编写CGI的语言有perl、php、python等,java也一样能写,但java的servlet完全能实现CGI的功能,且更优化、更利于开发。
2.各种术语释疑
说实话,对于一个没接触过编程语言的人来说,刚接触cgi概念的时候肯定会有一堆疑问,这到底是什么鬼,处理动态内容的东西不是像php一样的应用程序吗,跟cgi有几毛钱关系,fastcgi又是什么?我想,非科班出身的强迫症患者(包括我)一定会被这些概念折腾的死去活来。
以php为例,我将一次动态请求相关的概念大致都简单解释一遍。
cgi
:它是一种协议。通过cgi协议,web server可以将动态请求和相关参数发送给专门处理动态内容的应用程序。fastcgi
:也是一种协议,只不过是cgi的优化版。cgi的性能较烂,fastcgi则在其基础上进行了改进。php-cgi
:fastcgi是一种协议,而php-cgi实现了这种协议。不过这种实现比较烂。它是单进程的,一个进程处理一个请求,处理结束后进程就销毁。php-fmp
:是对php-cgi的改进版,它直接管理多个php-cgi进程/线程。也就是说,php-fpm是php-cgi的进程管理器因此它也算是fastcgi协议的实现。在一定程度上讲,php-fpm与php的关系,和tomcat对java的关系是类似的。cgi进程/线程
:在php上,就是php-cgi进程/线程。专门用于接收web server的动态请求,调用并初始化zend虚拟机。cgi脚本
:被执行的php源代码文件。zend虚拟机
:对php文件做词法分析、语法分析、编译成opcode,并执行。最后关闭zend虚拟机。cgi进程/线程和zend虚拟机的关系
:cgi进程调用并初始化zend虚拟机的各种环境。
以php-fpm为例,web server从转发动态请求到结束的过程大致如下:
而每个php-cgi进程的作用大致包括:(有些功能分类错误,请无视,知道大致功能就够了)
注意,尽管php-fpm的全称为PHP FastCGI Process Manager,但严格地讲,php-fpm不是fastcgi的进程管理器,而是php fastcgi即php-cgi的进程管理器。fastcgi只是一种协议,不是进程。就像http协议一样,apache对它的实现是httpd,nginx对它的实现就叫nginx。
再次说明,cgi和fastcgi是一种协议。各种支持和WEB交互的编程语言对cgi/fastcgi协议都做了各自的实现(当然,任何一种语言都能写cgi脚本),而php上的php-cgi和php-fpm正是php对fastcgi协议的实现。
3. web server和CGI的交互模式
web server对cgi进程/线程来说,它的作用就是发起动态处理请求,传递一些参数和环境变量,最后接收cgi的返回结果。再通俗而不严谨地说,web server通过cgi/fastcgi协议将动态请求转发给执行cgi脚本的应用程序。通过下面httpd.conf中的转发配置应该很容易理解(httpd和php-fpm的交互):
ProxyRequests off
ProxyPassMatch ^/(.*\.php)$ fcgi://127.0.0.1:9000/usr/local/apache/htdocs/$1
以最典型的apache httpd和php为例,对于httpd来说,web server和php-cgi有3种交互模式。
cgi模式
:httpd接收到一个动态请求就fork一个cgi进程,cgi进程返回结果给httpd进程后自我销毁。动态模块模式
:将php-cgi的模块(例如php5_module)编译进httpd。在httpd启动时会加载模块,加载时也将对应的模块激活,php-cgi也就启动了。(注:纠正一个小小错误,很多人以为动态编译的模块是可以在需要的时候随时加载调用,不需要的时候它们就停止了,实际上不是这样的。和静态编译的模块一样,动态加载的模块在被加载时就被加入到激活链表中,无论是否使用它,它都已经运行在apache httpd的内部。可参考LoadModule指令的官方手册)php-fpm模式
:使用php-fpm管理php-cgi,此时httpd不再控制php-cgi进程的启动。可以将php-fpm独立运行在非web服务器上,实现所谓的动静分离。
实际上,借助模块mod_fastcgi还可以实现fastcgi模式。同cgi一样,管理模式的先天缺陷决定了这并不是一种好方法。
3.1 CGI模式
使用CGI模式时,当动态请求到达,httpd临时启动一个cgi解释器,并通过cgi协议转发要运行的内容。当cgi脚本运行结束后,将结果返回给httpd,然后cgi解释器进程自我销毁。当多个动态请求到达时,将先后启动多个cgi解释器。因此,这种方法效率极低。
在注释掉php5_module的LoadModule相关行后,使用action指令指定要使用cgi运行的类型。但注意,action指令是mod_action提供的,所以必须已经加载该模块。
例如:指定MIME类型为image/gif的请求使用images.cgi运行。显然,images.cgi脚本你必须先写好。
Action image/gif /cgi-bin/images.cgi
还可以通过添加handler来复合文件类型,再使用某个cgi脚本去运行这个handler中的任意类型。
AddHandler my-file-type .xyz
Action my-file-type "/cgi-bin/program.cgi"
对于php来说,则可以使用安装php时bin目录下提供的php-cgi程序作为cgi程序。
[root@xuexi php]# ls /usr/local/php/bin/
pear peardev pecl phar phar.phar php php-cgi php-config phpize
# 复制到apache默认的cgi-bin目录下,方便管理
[root@xuexi php]# cp /usr/local/php/bin/php-cgi /usr/local/apache/cgi-bin/
# 在httpd.conf中添加以下行
Action application/x-httpd-php /usr/local/php/bin/cgi-bin/php-cgi
3.2 模块方式
在编译php时,将php5_module模块编译到apache中,例如在编译php时在./configure配置中加上"--with-apxs2=/usr/local/apache/bin/apxs"。
这种交互模式下,httpd在启动时加载并激活php_module。也就是说,php-cgi常驻在httpd进程内部。当动态请求到达时,httpd不用再生成cgi解释器,而是直接将动态请求转发给它内部php-cgi。
配置实用这种交互模式非常简单,只需使用LoadModule加载php_module,再添加对应的MIME处理器即可。
LoadModule php5_module modules/libphp5.so
# 在mime模块中添加对应的类型
<IfModule mime_module>
AddType application/x-httpd-php .php
AddType applicaiton/x-httpd-php-source .phps
</IfModule>
3.3 php-fpm方式
前面说了,php-fpm是php-cgi的进程管理器。这种交互方式实际上是让php-cgi以独立于httpd的方式存在,目前基本使用php-fpm的方式管理php-cgi进程。也就是说,这种模式下,php-cgi和httpd已经分离了,它们的分离意味着请求的动静分离变为可能:httpd和php-fpm分别运行在不同服务器上。动静分离后,压力也分散到各自的服务器上。
要让php-fpm以这种方式运行,需要在编译的./configure配置选项中添加"--enable-fpm"选项。当然,还得启动php-fpm服务。例如:
service php-fpm start
这样php-cgi进程就开放着端口(默认9000)等待httpd转发动态请求。要让httpd能够转发请求到php-cgi上,需要在httpd.conf中关闭正向代理,并设置fastcgi协议代理参数。例如,转发到192.168.100.54主机上的php-fpm。
# 加载代理模块
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so
# 添加MIME类型
AddType application/x-httpd-php .php
AddType application/x-httpd-php-source .phps
# 在需要转发的虚拟主机中配置转发代理
ProxyRequests off
ProxyPassMatch ^/(.*\.php)$ fcgi://192.168.100.54:9000/usr/local/apache/htdocs/$1
简单说明CGI是什么的更多相关文章
- 写了一个简单的CGI Server
之前看过一些开源程序的源码,也略微知道些Apache的CGI处理程序架构,于是用了一周时间,用C写了一个简单的CGI Server,代码算上头文件,一共1200行左右,难度中等偏上,小伙伴可以仔细看看 ...
- 搭建简单的CGI应用程序
原文来源于<核心编程3>第10章web编程 一.静态文件+脚本文件 1.首先开启cgiweb服务器 python2 -m CGIHTTPServer 8000 看到如下反应 2.服务器目录 ...
- 简单说明CGI和动态请求是什么
1. CGI是什么 CGI是common gateway interface的缩写,大家都译作通用网关接口,但很不幸,我们无法见名知意. 我们知道,web服务器所处理的内容都是静态的,要想处理动态内容 ...
- 最简单理解CGI,FastCGI,WSGI
CGI规定了如何执行本地脚本技术规范(协议),FastCGI规定了如何远程请求执行脚本的技术规范,WSGI规定了如何请求执行Python脚本的规范. 他们的相同点就是envionment variab ...
- Ubuntu + Apache2 环境下用C编写 一个简单的cgi脚本
我只学习过c语言,没有学习过prel,网上很多教程都是针对prel的,很少有针对c的.自己在Ubuntu下鼓捣了一下午,也总算是用c成功编写了一个helloworld的cgi,算是cgi入门的第一步. ...
- C语言开发CGI程序的简单例子
这年头用C语言开发cgi的已经不多,大多数的web程序都使用java.php.python等这些语言了. 但是本文将做一些简单的cgi实例. 首先配置环境 #这里是使用的apache AddHandl ...
- apache通过cgi调用exe程序
windows下,使用c写了一个简单的cgi程序,生成exe类型的可执行文件,代码如下: #include<stdio.h> int main() { printf("Conte ...
- Nginx + CGI/FastCGI + C/Cpp
接着上篇<Nginx安装与使用>,本篇介绍CGI/FASTCGI的原理.及如何使用C/C++编写简单的CGI/FastCGI,最后将CGI/FASTCGI部署到nginx.内容大纲如下: ...
- 【转】初识CGI
一.基本原理 CGI:通用网关接口(Common Gateway Interface)是一个Web服务器主机提供信息服务的标准接口.通过CGI接口,Web服务器就能够获取客户端提交的信息,转交给服务器 ...
随机推荐
- C++中值传递、指针传递、引用传递的总结
C++中值传递.指针传递.引用传递的总结 指针传递和引用传递一般适用于:函数内部修改参数并且希望改动影响调用者.对比值传递,指针/引用传递可以将改变由形参"传给"实参(实际上就 ...
- Linux学习之路 -- 简单日常使用命令
tail -f catalina.out #在 logs 下面查看日志( -f 实时查看) rm -rf /var/log/httpd/access #删除文件(-r删除文件 并删除文件夹下的内容 - ...
- [js高手之路]Vue2.0基于vue-cli+webpack同级组件之间的通信教程
我们接着上文继续,本文我们讲解兄弟组件的通信,项目结构还是跟上文一样. 在src/assets目录下建立文件EventHandler.js,该文件的作用在于给同级组件之间传递事件 EventHandl ...
- 基于C语言的UTF-8中英文替换密码设计
简要说明 本设计为湖南大学密码学的一次课程作业设计.非作业目的可随意引用. 由于本人初次接触密码学,本设计可能存在问题以及漏洞.若发现望指出. GitHub : https://github.com/ ...
- ★浅谈Spanking情节
- 转:【深入Java虚拟机】之五:多态性实现机制——静态分派与动态分派
转载请注明出处:http://blog.csdn.net/ns_code/article/details/17965867 方法解析 Class文件的编译过程中不包含传统编译中的连接步骤,一切方法 ...
- [2017BUAA软工助教]第0次个人作业
学习别人的经验和体会 零.前言 我认为人生就是一次次地从<存在>到<光明>. 一.软件工程师的成长 0.这是一个博客索引 同学们在上这门课的时候基本都是大三,觉得在大学里,到教 ...
- Beta的计划和人员的变动
一.新的成员和组长是否重选: 刘光华:先加入的一个帅哥,乐于助人,编码基础不是很好,但是有一颗热爱学习的心,会积极主动的完成自己的任务的,一句话宣言:我们的团队是最棒的! 程志铭:做事认真负责,工作脚 ...
- 201521123055 《Java程序设计》第2周学习总结
1. 本章学习总结 (1)认识PATH和CLASSPATH (2)SET PATH/CLASSPATH和-cp的用法 (3)了解BigDecimal.BigInteger.ArrayList/Lis ...
- 201521123051《java程序设计》 第一周学习总结
1. 本章学习总结 Java可以算是从C++发展而来的,因此Java与C语言的语法应该是比较类似的.但通过初步学习1.java语言的发展过程 2.java的特点 系统简单,功能齐备. 3.java的三 ...