CGI(Common Gateway Interface)是一个Web做事器主机供应信息做事的标准接口。
通过CGI接口,Web做事器就能够获取客户端提交的信息,转交给做事器真个CGI程序进行处理,末了返回结果给客户端。
我们知道,web做事器所处理的内容都是静态的,要想处理动态内容,须要依赖于web运用程序,如php、jsp、python等。但是web server如何将动态的要求通报给这些运用程序?它所依赖的便是cgi协议。也便是web server和web运用程序互换时的规范。换句话说,通过cgi协议,再结合已搭建好的web运用程序,就可以让web server也能\"大众处理\"大众动态要求,你肯定知道处理两字为什么要加上双引号。
大略版的cgi事情办法如下:
例如,在浏览器中搜索一个关键词\"大众http\"大众,对应的URL为:
https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=0&rsv_idx=1&tn=baidu&wd=http&rsv_pq=ae0fdcf200028d17&rsv_t=ead5cgwZA%2FJcvKfh16x7TDRimaaqWVjLEXrpFCrFUO4EiMe1VSKd636fNu4&rqlang=cn&rsv_enter=1&rsv_sug3=4&rsv_sug1=4&rsv_sug7=100&rsv_sug2=0&inputT=1575&rsv_sug4=1576
当百度的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程序)。
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协议的实现。
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