简单说明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服务器就能够获取客户端提交的信息,转交给服务器 ...
随机推荐
- Grails笔记二:grails 2.4.3版本下generate-*失效问题解析
最近在学grails框架,因为其敏捷性让我非常喜欢,不过有点让人恼怒的是也许因为grails框架太新了,所以关于grails的书籍很少,而且市面上的书籍大部分都是2007或者2009年的,官方文档又都 ...
- 从源码分析java.lang.String.isEmpty()
今天在写代码的时候用到了java.lang.String.isEmpty()的这个方法,之前也用过,今天突发奇想,就看了看源码,了解了解它的实现方法,总结出来,大家可以交流交流. 通常情况下,我们使用 ...
- liunx下常见的命令汇总
前言:这篇文章对于工作多年的可能用处不大,但对于刚刚接触Java的同学肯定是有一些帮助,现在我总结我接触liunx后常见的一些命令 1:日志查询常用的命令 ll:查询目录下所有的文件 ls -lht: ...
- Mysql介绍和实践总结
本文首先介绍mysql的安装和基本使用.进阶操作.讲解mysql的导入导出和自动备份,然后介绍安全模式修改密码和mysql的全文本搜索功能,最后记录了个人使用mysql中遇到的问题集. 开始安装: s ...
- poj 2553 强连通
题意:给出一个有向图,定义:若节点v所有能到达的点{wi},都能反过来到达v,那么称节点v是sink.题目要求所有的sink点. 思路:强连通缩点找出出度为零的点,输出即可. 这题主要问题是读题,了解 ...
- sublime text3 3143 注册码
sublime text3 3143 注册码,可用~ Sublime Text一款具有代码高亮.语法提示.自动完成且反应快速的编辑器软件,不仅具有华丽的界面,还支持插件扩展机制.相比于难于上手的Vi ...
- FFmpeg 常用命令收集
FFmpeg 常用命令 合并视频 ffmpeg -i "KTDS-820A_FHD.mp4" -c copy -bsf:v h264_mp4toannexb -f mpegts i ...
- 【Beta】阶段 第五次Daily Scrum Meeting
每日任务 1.本次会议为第五次 Meeting会议: 2.本次会议在周五下午15:35,在禹洲楼召开,召开本次会议为10分钟. 一.今日站立式会议照片 二.每个人的工作 (有work item 的ID ...
- 团队作业八——第二次团队冲刺(Beta版本)第3天
一.每个人的工作 (1) 昨天已完成的工作 对界面进行完善,并增加简单界面(包含简单界面内含的界面),简单模式与复杂模式的选择界面. (2) 今天计划完成的工作 做一下用户注册的功能和登录功能. (3 ...
- 【Alpha阶段】第五次scrum meeting
一.会议照片 二.会议内容 姓名 学号 负责模块 昨日任务完成度 今日任务 杨爱清 099 界面设计和交互功能 完成 去酷狗选择合适的轻音乐 杨立鑫 100 数据库搭建和其他 完成 继续对数据库进行编 ...