Nginx + CGI/FastCGI + C/Cpp
2015-12-04 13:38
573 查看
Nginx+CGI/FastCGI+C/Cpp
2014-12-1911:05by吴秦,8859阅读,4评论,接着上篇《
1.CGI
1.1.环境变量
1.2.标准输入
2.FastCGI
3.nginxcgi/fastcgi
3.1.nginx+fastcgi
3.1.1.spawn-fcgi
3.1.2.编写fastcgi应用程序
3.1.3.nginxfastcgi配置
3.2.nginx+cgi
3.2.1fastcgi-wrapper
3.2.2.nginxfcgiwrap配置
3.2.3.编写cgi应用程序
参考链接
1.CGI
通用网关接口(CommonGatewayInterface/CGI)描述了客户端和服务器程序之间传输数据的一种标准,可以让一个客户端,从网页浏览器向执行在网络服务器上的程序请求数据。CGI独立于任何语言的,CGI程序可以用任何最初,CGI是在1993年由美国
lstep1.web服务器收到客户端(浏览器)的请求HttpRequest,启动CGI程序,并通过环境变量、标准输入传递数据
lstep2.cgi进程启动解析器、加载配置(如业务相关配置)、连接其它服务器(如数据库服务器)、逻辑处理等
lstep3.cgi程将处理结果通过标准输出、标准错误,传递给web服务器
lstep4.web服务器收到cgi返回的结果,构建HttpResponse返回给客户端,并杀死cgi进程
web服务器与cgi通过环境变量、标准输入、标准输出、标准错误互相传递数据。
1.1.环境变量
GET请求,它将数据打包放置在环境变量QUERY_STRING中,CGI从环境变量QUERY_STRING中获取数据。常见的环境变量如下表所示:环境变数 | 内容 |
AUTH_TYPE | 存取认证类型。 |
CONTENT_LENGTH | 由标准输入传递给CGI程序的数据长度,以bytes或字元数来计算。 |
CONTENT_TYPE | 请求的MIME类型。 |
GATEWAY_INTERFACE | 服务器的CGI版本编号。 |
HTTP_ACCEPT | 浏览器能直接接收的Content-types,可以有HTTPAcceptheader定义. |
HTTP_USER_AGENT | 递交表单的浏览器的名称、版本和其他平台性的附加信息。 |
HTTP_REFERER | 递交表单的文本的URL,不是所有的浏览器都发出这个信息,不要依赖它 |
PATH_INFO | 传递给cgi程式的路径信息。 |
QUERY_STRING | 传递给CGI程式的请求参数,也就是用"?"隔开,添加在URL后面的字串。 |
REMOTE_ADDR | client端的host名称。 |
REMOTE_HOST | client端的IP位址。 |
REMOTE_USER | client端送出来的使用者名称。 |
REMOTE_METHOD | client端发出请求的方法(如get、post)。 |
SCRIPT_NAME | CGI程式所在的虚拟路径,如/cgi-bin/echo。 |
SERVER_NAME | server的host名称或IP地址。 |
SERVER_PORT | 收到request的server端口。 |
SERVER_PROTOCOL | 所使用的通讯协定和版本编号。 |
SERVER_SOFTWARE | server程序的名称和版本。 |
1.2.标准输入
环境变量的大小是有一定的限制的,当需要传送的数据量大时,储存环境变量的空间可能会不足,造成数据接收不完全,甚至无法执行CGI程序。因此后来又发展出另外一种方法:POST,也就是利用I/O重新导向的技巧,让CGI程序可以由STDIN和STDOUT直接跟浏览器沟通。
当我们指定用这种方法传递请求的数据时,web服务器收到数据后会先放在一块输入缓冲区中,并且将数据的大小记录在CONTENT_LENGTH这个环境变数,然后调用CGI程式并将CGI程序的STDIN指向这块缓冲区,于是我们就可以很顺利的通过STDIN和环境变数CONTENT_LENGTH得到所有的资料,再没有资料大小的限制了。
总结:CGI使外部程序与Web服务器之间交互成为可能。CGI程式运行在独立的进程中,并对每个Web请求建立一个进程,这种方法非常容易实现,但效率很差,难以扩展。面对大量请求,进程的大量建立和消亡使操作系统性能大大下降。此外,由于地址空间无法共享,也限制了资源重用。
2.FastCGI
快速通用网关接口(FastCommonGatewayInterface/FastCGI)是当进来一个请求时,Web服务器把环境变量和这个页面请求通过一个unixdomainsocket(都位于同一物理服务器)或者一个IPSocket(FastCGI部署在其它物理服务器)传递给FastCGI进程。
lstep1.Web服务器启动时载入初始化FastCGI执行环境。例如IISISAPI、apachemod_fastcgi、nginxngx_http_fastcgi_module、lighttpdmod_fastcgi
lstep2.FastCGI进程管理器自身初始化,启动多个CGI解释器进程并等待来自Web服务器的连接。启动FastCGI进程时,可以配置以ip和UNIX域socket两种方式启动。
lstep3.当客户端请求到达Web服务器时,Web服务器将请求采用socket方式转发到FastCGI主进程,FastCGI主进程选择并连接到一个CGI解释器。Web服务器将CGI环境变量和标准输入发送到FastCGI子进程。
lstep4.FastCGI子进程完成处理后将标准输出和错误信息从同一socket连接返回Web服务器。当FastCGI子进程关闭连接时,请求便处理完成。
lstep5.FastCGI子进程接着等待并处理来自Web服务器的下一个连接。
由于FastCGI程序并不需要不断的产生新进程,可以大大降低服务器的压力并且产生较高的应用效率。它的速度效率最少要比CGI技术提高5倍以上。它还支持分布式的部署,即FastCGI程序可以在web服务器以外的主机上执行。
总结:CGI就是所谓的短生存期应用程序,FastCGI就是所谓的长生存期应用程序。FastCGI像是一个常驻(long-live)型的CGI,它可以一直执行着,不会每次都要花费时间去fork一次(这是CGI最为人诟病的fork-and-execute模式)。
3.nginxcgi/fastcgi
nginx不能像apache那样直接执行外部可执行程序,但nginx可以作为代理服务器,将请求转发给后端服务器,这也是nginx的主要作用之一。其中nginx就支持FastCGI代理,接收客户端的请求,然后将请求转发给后端fastcgi进程。下面介绍如何使用C/C++编写cgi/fastcgi,并部署到nginx中。3.1.nginx+fastcgi
通过前面的介绍知道,fastcgi进程由FastCGI进程管理器管理,而不是nginx。这样就需要一个FastCGI管理,管理我们编写fastcgi程序。本文使用spawn-fcgi作为FastCGI进程管理器。3.1.1.spawn-fcgi
spawn-fcgi是一个通用的FastCGI进程管理器,简单小巧,原先是属于lighttpd的一部分,后来由于使用比较广泛,所以就迁移出来作为独立项目了。spawn-fcgi使用pre-fork模型,功能主要是打开监听端口,绑定地址,然后fork-and-exec创建我们编写的fastcgi应用程序进程,退出完成工作。fastcgi应用程序初始化,然后进入死循环侦听socket的连接请求。安装spawn-fcgi:
l获取spawn-fcgi编译安装包,在
l解压缩spawn-fcgi-x.x.x.tar.gz包。
l进入解压缩目录,执行./configure。
lmake&makeinstall
如果遇到以下错误:“./autogen.sh:x:autoreconf:notfound”,因为没有安装automake工具,ubuntu用下面的命令安装好就可以了:sudoapt-getinstallautoconfautomakelibtool。
spawn-fcgi的帮助信息可以通过manspawn-fcgi或spawn-fcgi–h获得,下面是部分常用spawn-fcgi参数信息:
-f<fcgiapp>指定调用FastCGI的进程的执行程序位置 -a<addr>绑定到地址addr。 -p<port>绑定到端口port。 -s<path>绑定到unixdomainsocket -C<childs>指定产生的FastCGI的进程数,默认为5。(仅用于PHP) -P<path>指定产生的进程的PID文件路径。 -F<childs>指定产生的FastCGI的进程数(C的CGI用这个) -u和-gFastCGI使用什么身份(-u用户-g用户组)运行,CentOS下可以使用apache用户,其他的根据情况配置,如nobody、www-data等。 |
3.1.2.编写fastcgi应用程序
使用C/C++编写fastcgi应用程序,可以使用FastCGI软件开发套件或者其它开发框架,如fastcgi++。本文使用FastCGI软件开发套件——fcgi(
l获取fcgi编译安装包,在
l解压缩fcgi-x.x.x.tar.gz包。
l进入解压缩目录,执行./configure。
lmake&makeinstall
如果编译提示一下错误:
fcgio.cpp:Indestructor'virtualfcgi_streambuf::~fcgi_streambuf()':
fcgio.cpp:50:error:'EOF'wasnotdeclaredinthisscope
fcgio.cpp:Inmemberfunction'virtualintfcgi_streambuf::overflow(int)':
fcgio.cpp:70:error:'EOF'wasnotdeclaredinthisscope
fcgio.cpp:75:error:'EOF'wasnotdeclaredinthisscope
fcgio.cpp:Inmemberfunction'virtualintfcgi_streambuf::sync()':
fcgio.cpp:86:error:'EOF'wasnotdeclaredinthisscope
fcgio.cpp:87:error:'EOF'wasnotdeclaredinthisscope
fcgio.cpp:Inmemberfunction'virtualintfcgi_streambuf::underflow()':
fcgio.cpp:113:error:'EOF'wasnotdeclaredinthisscope
make[2]:***[fcgio.lo]Error1
make[2]:Leavingdirectory`/root/downloads/fcgi-2.4.1-SNAP-0910052249/libfcgi'
make[1]:***[all-recursive]Error1
make[1]:Leavingdirectory`/root/downloads/fcgi-2.4.1-SNAP-0910052249'
make:***[all]Error2
解决办法:在/include/fcgio.h文件中加上#include<cstdio>,然后再编译安装就通过了。
如果提示找不到动态库,请在LD_LIBRARY_PATH或/etc/ld.so.conf中添加fcgi的安装路径,如/usr/local/lib,并执行ldconfig更新一下。
#include"fcgi_stdio.h"
#include<stdlib.h>
intmain(void)
{
intcount=0;
while(FCGI_Accept()>=0)
printf("Content-type:text/html\r\n"
"\r\n"
"<title>FastCGIHello!</title>"
"<h1>FastCGIHello!</h1>"
"Requestnumber%drunningonhost<i>%s</i>\n",
++count,getenv("SERVER_NAME"));
return0;
}
编译g++main.cpp-odemo–lfcgi,并将demo部署到/opt/nginx-1.7.7/cgi-bin/目录
通过spawn-fcgi启动c/c++编写好的fastcgi程序:/opt/nginx-1.7.7/sbin/spawn-fcgi-a127.0.0.1-p8081-f/opt/nginx-1.7.7/cgi-bin/demo
3.1.3.nginxfastcgi配置
关于nginx的几个配置文件解析,可以参阅《这样nginx收到
3.2.nginx+cgi
nginx不能直接执行外部可执行程序,并且cgi是接收到请求时才会启动cgi进程,不像fastcgi会在一开就启动好,这样nginx天生是不支持cgi的。nginx虽然不支持cgi,但它支持fastCGI。所以,我们可以考虑使用fastcgi包装来支持cgi。原理大致如下图所示:pre-fork几个通用的代理fastcgi程序——fastcgi-wrapper,fastcgi-wrapper启动执行cgi然后将cgi的执行结果返回给nginx(fork-and-exec)。明白原理之后,编写一个fastcgi-warpper也比较简单。网上流传比较多的一个解决方案是,来自nginxwiki(
3.2.1.fastcgi-wrapper
其实编写C/C++的fastcgi-wrapper,就是写一个C/C++的fastcgi,步骤和原理跟前面的小节(nginx+fastcgi)一样。github上已经有人开源了,C写的fastcgi-wrapper:安装fcgiwrap:
l下载(
l解压缩fcgiwrap,进入解压目录
lautoreconf-i
l./configure
lmake&&makeinstall
启动fastcgi-wrapper:/opt/nginx-1.7.7/sbin/spawn-fcgi-f/usr/local/sbin/fcgiwrap-p8081
3.2.2.nginxfcgiwrap配置
在nginx.conf中增加下面的loaction配置块,这样所有的xxx.cgi请求都会走到fcgiwrap,然后fcgiwrap会执行cgi-bin目录下的cgi程序。3.2.3.编写cgi应用程序
#include<stdio.h>#include<stdlib.h>
intmain(void)
{
intcount=0;
printf("Content-type:text/html\r\n"
"\r\n"
"<title>CGIHello!</title>"
"<h1>CGIHello!</h1>"
"Requestnumber%drunningonhost<i>%s</i>\n",
++count,getenv("SERVER_NAME"));
return0;
}
tyler@ubuntu:~/ClionProjects/HelloFastCGI$g++cgi.cpp-ocgidemo-lfcgi
tyler@ubuntu:~/ClionProjects/HelloFastCGI$sudocpcgidemo/opt/nginx-1.7.7/cgi-bin/
注意图中的请求次数一直都是1,因为cgi的模式是fork-and-exec,每次都是一个新的进程。
参考链接
lCGI,lfastcgi,
lspawn-fcgi,
lfcgi,
lfcgiwrap,
相关文章推荐
- 使用nginx为图片进行水印操作
- install nginx in centos
- install nginx in centos
- nginx 的安装
- nginx 源码学习笔记(二十三)—— event 模块(四) ——timer红黑树
- nginx 源码学习笔记(二十二)—— event 模块(三) ——epoll模块
- nginx 源码学习笔记(二十一)—— event 模块(二) ——事件驱动核心ngx_process_events_and_timers
- nginx 源码学习笔记(二十)—— event 模块(一) ——初始化
- nginx 源码学习笔记(十九)—— nginx启动过程函数调用图
- nginx 源码学习笔记(十八)—— ngx_add_inherited_sockets 继承的sockets
- CentOS+nginx+uwsgi+Python+django 环境搭建
- Centos6.5安装及简单配置nginx
- Nginx代理功能(未完)
- nginx 源码学习笔记(十七)—— ngx_worker_process_cycle子进程执行
- 【django】Nginx+uWSGI+Django部署我的博客网站
- nginx是以多进程的方式来工作的
- 使用vim打开某文件一直出现Swap file ".nginx.conf.swp" already exists!
- nginx防止SQL注入规则
- Nginx加载多个CPU核心,worker_cpu_affinity
- nginx 全面优化 负载均衡