Nginx + CGI/FastCGI + C/Cpp

文章目录

  • 1.CGI
    • 1.1.环境变量
    • 1.2.标准输入
    • 总结:CGI使外部程序与Web服务器之间交互成为可能。CGI程式运行在独立的进程中,并对每个Web请求建立一个进程,这种方法非常容易实现,但效率很差,难以扩展。面对大量请求,进程的大量建立和消亡使操作系统性能大大下降。此外,由于地址空间无法共享,也限制了资源重用。
  • 2.FastCGI
  • 3.nginx cgi/fastcgi
    • 3.1. nginx + fastcgi
      • 3.1.1. spawn-fcgi
      • 3.1.2. 编写fastcgi应用程序
      • 3.1.3. nginx fastcgi配置
    • 3.2. nginx + cgi
      • 3.2.1. fastcgi-wrapper
      • 3.2.2. nginx fcgiwrap配置

接着上篇《Nginx安装与使用》,本篇介绍CGI/FASTCGI的原理、及如何使用C/C++编写简单的CGI/FastCGI,最后将CGI/FASTCGI部署到nginx。内容大纲如下:

1.CGI

通用网关接口(Common Gateway Interface/CGI)描述了客户端和服务器程序之间传输数据的一种标准,可以让一个客户端,从网页浏览器向执行在网络服务器上的程序请求数据。CGI 独立于任何语言的,CGI 程序可以用任何脚本语言或者是完全独立编程语言实现,只要这个语言可以在这个系统上运行。Unix shell script, Python, Ruby, PHP, perl, Tcl, C/C++, 和 Visual Basic 都可以用来编写 CGI 程序。(http://www.dwz.cn/yFFgQ)

最初,CGI 是在 1993 年由美国国家超级电脑应用中心(NCSA)为 NCSA HTTPd Web 服务器开发的。这个 Web 服务器使用了 UNIX shell 环境变量 来保存从 Web 服务器传递出去的参数,然后生成一个运行 CGI 的独立的进程。cgi的处理流程如下图所示:

  • step1. web 服务器收到客户端(浏览器)的请求Http Request,启动CGI程序,并通过环境变量、标准输入传递数据

  • step2. cgi进程启动解析器、加载配置(如业务相关配置)、连接其它服务器(如数据库服务器)、逻辑处理等

  • step3. cgi进程将处理结果通过标准输出、标准错误,传递给web 服务器

  • step4. web 服务器收到cgi返回的结果,构建Http Response返回给客户端,并杀死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, 可以有HTTP Accept header定义.HTTP_USER_AGENT递交表单的浏览器的名称、版本 和其他平台性的附加信息。HTTP_REFERER递交表单的文本的 URL,不是所有的浏览器都发出这个信息,不要依赖它PATH_INFO传递给cgi程式的路径信息。QUERY_STRING传递给CGI程式的请求参数,也就是用"?"隔开,添加在URL后面的字串。REMOTE_ADDRclient端的host名称。REMOTE_HOSTclient端的IP位址。REMOTE_USERclient端送出来的使用者名称。REMOTE_METHODclient端发出请求的方法(如get、post)。SCRIPT_NAMECGI程式所在的虚拟路径,如/cgi-bin/echo。SERVER_NAMEserver的host名称或IP地址。SERVER_PORT收到request的server端口。SERVER_PROTOCOL所使用的通讯协定和版本编号。SERVER_SOFTWAREserver程序的名称和版本。

1.2.标准输入

环境变量的大小是有一定的限制的,当需要传送的数据量大时,储存环境变量的空间可能会不足,造成数据接收不完全,甚至无法执行CGI程序。因此后来又发展出另外一种方法:POST,也就是利用I/O重新导向的技巧,让CGI程序可以由STDIN和STDOUT直接跟浏览器沟通。

当我们指定用这种方法传递请求的数据时,web 服务器收到数据后会先放在一块输入缓冲区中,并且将数据的大小记录在CONTENT_LENGTH这个环境变数,然后调用CGI程式并将CGI程序的STDIN指向这块缓冲区,于是我们就可以很顺利的通过STDIN和环境变数CONTENT_LENGTH得到所有的资料,再没有资料大小的限制了。

总结:CGI使外部程序与Web服务器之间交互成为可能。CGI程式运行在独立的进程中,并对每个Web请求建立一个进程,这种方法非常容易实现,但效率很差,难以扩展。面对大量请求,进程的大量建立和消亡使操作系统性能大大下降。此外,由于地址空间无法共享,也限制了资源重用。

2.FastCGI

快速通用网关接口(Fast Common Gateway Interface/FastCGI)是通用网关接口(CGI)的改进,描述了客户端和服务器程序之间传输数据的一种标准。FastCGI致力于减少Web服务器与CGI程式之间互动的开销,从而使服务器可以同时处理更多的Web请求。与为每个请求创建一个新的进程不同,FastCGI使用持续的进程来处理一连串的请求。这些进程由FastCGI进程管理器管理,而不是web服务器。(http://www.dwz.cn/yFMap)


当进来一个请求时,Web 服务器把环境变量和这个页面请求通过一个unix domain socket(都位于同一物理服务器)或者一个IP Socket(FastCGI部署在其它物理服务器)(就是我们的效果)传递给FastCGI进程。

  • step1. Web 服务器启动时载入初始化FastCGI执行环境 。 例如IIS ISAPI、apache mod_fastcgi、nginx ngx_http_fastcgi_module、lighttpd mod_fastcgi

  • step2. FastCGI进程管理器自身初始化,启动多个CGI解释器进程并等待来自Web 服务器的连接。 启动FastCGI进程时,可以配置以ip和UNIX 域socket两种方式启动。

UNIX 域套接字
1、UNIX 域套接字以 UNIX 路径命名。例如,可以将套接字命名为 /tmp/foo。UNIX 域套接字只在一台主机上的进程之间通信。UNIX 域中的套接字不会被视为网络协议的一部分,因为它们只能用于在一台主机上的进程之间通信。
2、套接字类型定义对于用户可见的通信属性。Internet 域套接字提供对 TCP/IP 传输协议的访问。Internet 域由值 AF_INET 标识。套接字仅与同一域中的套接字交换数据。
参考文章:UNIX 域套接字

  • step3. 当客户端请求到达Web 服务器时, Web 服务器将请求采用socket方式转发到 FastCGI主进程,FastCGI主进程选择并连接到一个CGI解释器。Web 服务器将CGI环境变量和标准输入发送到FastCGI子进程。

  • step4. FastCGI子进程完成处理后将标准输出和错误信息从同一socket连接返回Web 服务器。当FastCGI子进程关闭连接时,请求便处理完成。

  • step5. FastCGI子进程接着等待并处理来自Web 服务器的下一个连接。

由于 FastCGI 程序并不需要不断的产生新进程,可以大大降低服务器的压力并且产生较高的应用效率。它的速度效率最少要比CGI 技术提高 5 倍以上。它还支持分布式的部署, 即 FastCGI 程序可以在web 服务器以外的主机上执行。(我们现在不就这么做的吗?Web服务器是单独主机,FastCGI烧在瑞芯微芯片摄像头模组里)

总结:CGI 就是所谓的短生存期应用程序,FastCGI 就是所谓的长生存期应用程序。FastCGI像是一个常驻(long-live)型的CGI,它可以一直执行着,不会每次都要花费时间去fork一次(这是CGI最为人诟病的fork-and-execute 模式)。

3.nginx cgi/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:

  • 获取spawn-fcgi编译安装包,在http://redmine.lighttpd.net/projects/spawn-fcgi/wiki上可以获取当前最新的版本。

  • 解压缩spawn-fcgi-x.x.x.tar.gz包。

  • 进入解压缩目录,执行./configure。

  • make & make install

(如果编译报错先chmod 777 * -R试试)

如果遇到以下错误:“ ./autogen.sh: x: autoreconf: not found”,因为没有安装automake 工具,ubuntu用下面的命令安装好就可以了:sudo apt-get install autoconf automake libtool 。

spawn-fcgi的帮助信息可以通过man spawn-fcgispawn-fcgi -h获得,下面是部分常用spawn-fcgi参数信息:

-f <fcgiapp> 指定调用FastCGI的进程的执行程序位置-a <addr> 绑定到地址addr。-p <port> 绑定到端口port。-s <path> 绑定到unix domain socket-C <childs> 指定产生的FastCGI的进程数,默认为5。(仅用于PHP)-P <path> 指定产生的进程的PID文件路径。-F <childs> 指定产生的FastCGI的进程数(C的CGI用这个)-u和-g FastCGI使用什么身份(-u 用户 -g 用户组)运行,CentOS下可以使用apache用户,其他的根据情况配置,如nobody、www-data等。

3.1.2. 编写fastcgi应用程序

使用C/C++编写fastcgi应用程序,可以使用FastCGI软件开发套件或者其它开发框架,如fastcgi++。

本文使用FastCGI软件开发套件——fcgi(http://www.fastcgi.com/drupal/node/6?q=node/21),通过此套件可以轻松编写fastcgi应用程序,

安装fcgi:

  • 获取fcgi编译安装包,在http://www.fastcgi.com/drupal/node/5上可以获取当前最新的版本。(我试了试网站访问不上。。。访问这个?https://fastcgi-archives.github.io/)

https://github.com/FastCGI-Archives

http://web.archive.org/web/20160316080434/http://www.fastcgi.com/drupal/node/5


下不到,蛋疼!

不知道这个能用不?https://github.com/FastCGI-Archives/FastCGI.com/tree/master/original_snapshot

  • 解压缩fcgi-x.x.x.tar.gz包。

  • 进入解压缩目录,执行./configure。

  • make & make install

如果编译提示以下错误:

fcgio.cpp: In destructor 'virtual fcgi_streambuf::~fcgi_streambuf()':fcgio.cpp:50: error: 'EOF' was not declared in this scopefcgio.cpp: In member function 'virtual int fcgi_streambuf::overflow(int)':fcgio.cpp:70: error: 'EOF' was not declared in this scopefcgio.cpp:75: error: 'EOF' was not declared in this scopefcgio.cpp: In member function 'virtual int fcgi_streambuf::sync()':fcgio.cpp:86: error: 'EOF' was not declared in this scopefcgio.cpp:87: error: 'EOF' was not declared in this scopefcgio.cpp: In member function 'virtual int fcgi_streambuf::underflow()':fcgio.cpp:113: error: 'EOF' was not declared in this scopemake[2]: *** [fcgio.lo] Error 1make[2]: Leaving directory `/root/downloads/fcgi-2.4.1-SNAP-0910052249/libfcgi'make[1]: *** [all-recursive] Error 1make[1]: Leaving directory `/root/downloads/fcgi-2.4.1-SNAP-0910052249'
make: *** [all] Error 2

解决办法:在/include/fcgio.h文件中加上 #include ,然后再编译安装就通过了。(尝试加进去了,还报错)

如果提示找不到动态库,请在LD_LIBRARY_PATH或/etc/ld.so.conf中添加fcgi的安装路径,如/usr/local/lib,并执行ldconfig更新一下。

ar:我先把fcgi文件包拷贝到这个路径下

[root@ubuntu /home/arnold/Arnold_test]1# mv 20211109_fcgi/ /usr/local/lib/

ar:然后添加环境变量

方法三:这个没有修改LD_LIBRARY_PATH但是效果是一样的实现动态库的查找,

  1. /etc/ld.so.conf下面加一行/usr/local/lib/20211109_fcgi
  2. 保存后执行 ldconfig 生效

参考文章:Linux环境变量设置方法总结 PATH、LD_LIBRARY_PATH

编不过去,不搞了!

#include "fcgi_stdio.h"#include <stdlib.h>int main(void){int count = 0;while (FCGI_Accept() >= 0)printf("Content-type: text/html\r\n""\r\n""<title>FastCGI Hello!</title>""<h1>FastCGI Hello!</h1>""Request number %d running on host <i>%s</i>\n",++count, getenv("SERVER_NAME"));return 0;}

编译g++ main.cpp -o demo –lfcgi,并将demo部署到/opt/nginx-1.7.7/cgi-bin/目录

通过spawn-fcgi启动c/c++编写好的fastcgi程序:/opt/nginx-1.7.7/sbin/spawn-fcgi -a 127.0.0.1 -p 8081 -f /opt/nginx-1.7.7/cgi-bin/demo

3.1.3. nginx fastcgi配置

关于nginx的几个配置文件解析,可以参阅《Nginx安装与使用》http://www.cnblogs.com/skynet/p/4146083.html,在上篇的nginx.conf基础上增加下面的fastcgi配置。


这样nginx收到http://localhost/demo.cgi请求时,会匹配到location = /demo.cgi块,将请求传到后端的fastcgi应用程序处理。如下如所示:(注意其中number为80,是因为我请求了80次)

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也比较简单。网上流传比较多的一个解决方案是,来自nginx wiki(http://wiki.nginx.org/SimpleCGI)上的使用perl的fastcgi包装脚本cgiwrap-fcgi.pl。但我对perl不是很感冒,下面给出一个C/C++写的fastcgi-wrapper。

3.2.1. fastcgi-wrapper

其实编写C/C++的fastcgi-wrapper,就是写一个C/C++的fastcgi,步骤和原理跟前面的小节(nginx+fastcgi)一样。github上已经有人开源了,C写的fastcgi-wrapper:

https://github.com/gnosek/fcgiwrap

安装fcgiwrap:

  • 下载(https://github.com/gnosek/fcgiwrap.git)

这依赖也太多了,我上面就是被这依赖搞晕的,我直接放弃。。。

  • 解压缩fcgiwrap,进入解压目录

  • autoreconf -i

  • ./configure

  • make && make install

启动fastcgi-wrapper:/opt/nginx-1.7.7/sbin/spawn-fcgi -f /usr/local/sbin/fcgiwrap -p 8081

3.2.2. nginx fcgiwrap配置

在nginx.conf中增加下面的loaction配置块,这样所有的xxx.cgi请求都会走到fcgiwrap,然后fcgiwrap会执行cgi-bin目录下的cgi程序。

Nginx + CGI/FastCGI + C/Cpp(编不过去,不搞了。。。)(Common Gateway Interface)相关推荐

  1. Nginx + CGI/FastCGI + C/Cpp

    http://www.cnblogs.com/skynet/p/4173450.html Nginx + CGI/FastCGI + C/Cpp 2014-12-19 11:05 by 吴秦, 197 ...

  2. CGI,FastCGI,spawn-fcgi,nginx组合使用

    目录 fastCGI 1. CGI 1.1 简介 1.2 CGI处理流程 1.3 环境变量 1.4 标准输入 1.5 CGI程序结构 1.6 测试 2. FastCGI 2.1 什么是FastCGI ...

  3. Nginx运行FastCGI程序(ngx_http_fastcgi_module模块、fcgi库、spwan-fcgi进程管理器)

    一.什么是CGI 通用网关接口(Common Gateway Interface.CGI)描述了客户端和服务器程序之间传输数据的一种标准,可以让一个客户端,从网页浏览器向执行在网络服务器上的程序请求数 ...

  4. nginx、fastCGI、php-fpm关系梳理(转载参考)

    nginx.fastCGI.php-fpm关系梳理 还可以参考:http://www.cnblogs.com/skynet/p/4173450.html 前言: Linux下搭建nginx+php+m ...

  5. 漫谈CGI FastCGI WSGI

    作者:auxten 链接:https://zhuanlan.zhihu.com/p/20054757 来源:知乎 著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. CGI(Comm ...

  6. linux下nginx+python+fastcgi部署总结(web.py版)

    2019独角兽企业重金招聘Python工程师标准>>> 在上一篇文章linux下nginx+python+fastcgi部署总结(django版)中,我们部署了nginx+djang ...

  7. Nginx+php+fastcgi的原理与关系

    一.用户对动态PHP网页访问过程 用户浏览器发起对网页的访问:http://192.168.1.103/index.php 用户和nginx服务器进行三次握手进行TCP连接(忽略包括nginx访问控制 ...

  8. windows下nginx+mono+fastCGI部署asp.net网站

    1,什么是nginx 简介 Nginx ("engine x") 是一个高性能的 HTTP 和 反向代理 服务器,也是一个 IMAP/POP3/SMTP 代理服务器. Nginx ...

  9. 架构 Varnish+Nginx+PHP(FastCGI)+MYSQL5+MemCache

    说明:        我在设计系统架构时,进行了大胆的尝试,只用6台Web服务器,达到了可承受4000万PV(页面访问量)的性能: 抛弃了 Apache,因为它能承受的并发连接相对较低: 抛弃了 Sq ...

最新文章

  1. 四月青少年编程组队学习(图形化四级)Task05
  2. 阿里宣布Atlas正式开源:带你重返App开发的田园时代
  3. Mysql中字段类型不一致导致索引无效
  4. 【F12一下,看看页面里的第一行】——说说浏览器兼容性模式
  5. 当你和你女朋友闹矛盾时......
  6. JdbcTemplate(操作数据库-添加功能)
  7. 循环小数与费马小定理
  8. 选项类 oracle ebs,Oracle EBS 打3类补丁主要步骤
  9. python3读取linux文件,Python3读取文件小技巧
  10. element table批量删除_element ui 批量删除
  11. IAR使用技巧 之 快捷键批量更换指定字符(以及Keil的全局替换功能)
  12. 在QTableWidget中添加QCheckBox并使其居中显示(转)
  13. fatal error C1010: 在查找预编译头时遇到意外的文件结尾
  14. js实现canvas在线画板
  15. html制作频谱,HTML5 WebAudioAPI(三)--绘制频谱图
  16. 网络游戏(MMORPG) 好玩的原因
  17. 从零到一写一个完整的 Compose 版本的天气
  18. 类模板和函数模板的区别及其应用案例 c++ 简单易懂
  19. 十月3倍销量于特斯拉的比亚迪,新增量在何处?
  20. 计算机后台 鼠标灯不亮,开机一直黑屏键盘鼠标灯不亮

热门文章

  1. linux和windows中insert语句注意
  2. jquery ajax设置头部,jQuery Ajax 设置请求头
  3. 增强——BTE流程简介
  4. 【转】简单介绍几个CDS视图聚合函数
  5. REM重复制造的冲销
  6. ABAP-AVL-OO方法中的ALV的如何自己添加按钮及其响应
  7. SAP SD:SAP信贷出口
  8. SAP根据用户名查姓名
  9. OLAP是什么意思?
  10. 与客户有关的业务数据表名,及删除客户主数据方法