CGI(common gateway interface)通用网关接口描述了客户端和服务器程序之间传输数据的⼀种标准,可以让⼀个客户端,从⽹⻚浏览器向执⾏在⽹络服务器上的程序请求数据。
CGI独⽴于任何语⾔的,CGI程序可以⽤任何脚本语⾔或者是完全独⽴编程语⾔实现,只要这个语⾔可以在这个系统上运⾏。Unix shell script、Python、 Ruby、PHP、 perl、Tcl、 C/C++和 Visual Basic 都可以⽤来编写CGI程序。
最初,CGI是在1993年由美国国家超级电脑应⽤中⼼(NCSA)为NCSA HTTPd Web服务器开发的。这个Web服务器使⽤了UNIX shell环境变量来保存从Web服务器传递出去的参数,然后⽣成⼀个运⾏CGI的独⽴的进程。
web浏览器 web浏览器
| |
|1.http request |4.http response
| |
web服务器 web服务器
| |
|2.stdin |3.stdout,stderr
| |
启动CGI解析器 -> 加载配置 -> 连接其他服务器 -> 逻辑处理 -> 退出
GET请求它将数据打包放置在环境变量QUERY_STRING中,可以通过getenv(“QUERY_STRING”)函数获取数据。
环境变数 | 含义 |
---|---|
AUTH_TYPE | 存取认证类型 |
CONTENT_LENGTH | 由标准输⼊传递给CGI程序的数据⻓度,以bytes或字元数来计算 |
CONTENT_TYPE | 请求的MIME类型 |
GATEWAY_INTERFAC E | 服务器的CGI版本编号 |
HTTP_ACCEPT | 浏览器能直接接收的Content-types, 可以有HTTP Accept header定义 |
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程序的名称和版本 |
环境变量的⼤⼩是有⼀定的限制的,当需要传送的数据量⼤时,储存环境变量的空间可能会不⾜,造成数据接收不完全,甚⾄⽆法执⾏CGI程序。
因此后来⼜发展出另外⼀种⽅法:POST,也就是利⽤I/O重新导向的技巧,让CGI程序可以由stdin和stdout直接跟浏览器沟通。
当我们指定⽤这种⽅法传递请求的数据时,web服务器收到数据后会先放在⼀块输⼊缓冲区中,并且将数据的⼤⼩记录在CONTENT_LENGTH这个环境变量,然后调⽤CGI程序并将CGI程序的stdin指向这块缓冲区,于是我们就可以很顺利的通过stdin和环境变数CONTENT_LENGTH得到所有的信息,再没有信息⼤⼩的限制了。
FastCGI(Fast Common Gateway Interface)快速通用网关接口,是通用网关接口CGI的改进。描述了客户端和服务器程序之间传输数据的⼀种标准。
FastCGI致⼒于减少Web服务器与CGI程式之间互动的开销,从⽽使服务器可以同时处理更多的Web请求。与为每个请求创建⼀个新的进程不同,FastCGI使⽤持续的进程来处理⼀连串的请求。这些进程由FastCGI进程管理器管理,⽽不是web服务器。
nginx服务⽀持FastCGI模式,能够快速⾼效地处理动态请求。⽽nginx对应的FastCGI模块为:ngx_http_fastcgi_module。
ngx_http_fastcgi_module模块允许将请求传递给FastCGI服务器。
FastCIG进程管理器:启动CGI解析器 -> 加载配置 -> 连接其他服务器 -> 进行循环
web浏览器
|1
web服务器
|2
FastCGI执行环境
|3
进入循环 -> 逻辑处理 -> 退出 -> 循环等待
|4
web服务器
|5
web浏览器
Nginx不能像Apache那样直接执⾏外部可执⾏程序,但Nginx可以作为代理服务器,将请求转发给后端服务器,这也是Nginx的主要作⽤之⼀。其中Nginx就⽀持FastCGI代理,接收客户端的请求,然后将请求转发给后端FastCGI进程。
由于FastCGI进程由FastCGI进程管理器管理,⽽不是Nginx。这样就需要⼀个FastCGI进程管理器,管理我们编写FastCGI程序。
spawn-fcgi是⼀个通⽤的FastCGI进程管理器,简单⼩巧,原先是属于lighttpd的⼀部分,后来由于使⽤⽐较⼴泛,所以就迁移出来作为独⽴项⽬。
spawn-fcgi使⽤pre-fork模型,功能主要是打开监听端⼝,绑定地址,然后fork-and-exec创建我们编写的FastCGI应⽤程序进程,退出完成⼯作。FastCGI应⽤程序初始化,然后进⼊死循环侦听socket的连接请求。
spawn-fcgi源码包下载地址:http://redmine.lighttpd.net/projects/spawn-fcgi/wiki
使⽤C/C++编写FastCGI应⽤程序,可以使⽤FastCGI软件开发套件或者其它开发框架,如fcgi。
fcgi下载地址:wget https://fossies.org/linux/www/old/fcgi-2.4.0.tar.gz
nginx需要在源码编译的时候加入fastcgi—module
location /test {
fastcgi_pass 127.0.0.1:8001;
fastcgi_index test;
include fastcgi.conf;
}
重新加载配置
/usr/local/nginx/sbin/nginx -s reload
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "fcgi_stdio.h"
int main(int argc, char *argv[])
{
int count = 0;
//阻塞等待并监听某个端⼝,等待Nginx将数据发过来
while (FCGI_Accept() >= 0)
{
//如果想得到数据,需要从stdin去读,实际上从Nginx上去读
//如果想上传数据,需要往stdout写,实际上是给Nginx写数据
printf("Content-type: text/html\r\n");
printf("\r\n");
printf("<title>Fast CGI Hello!</title>");
printf("<h1>Fast CGI Hello!</h1>");
//SERVER_NAME:得到server的host名称
printf("Request number %d running on host <i>%s</i>\n",
++count, getenv("SERVER_NAME"));
}
return 0;
}
root@VM-0-16-ubuntu:/usr/local/nginx/sbin# lsof -i:8001
root@VM-0-16-ubuntu:/usr/local/nginx/sbin# cd /home/workplace/0voice_tuchuang/learn_test/
root@VM-0-16-ubuntu:/home/workplace/0voice_tuchuang/learn_test# gcc fastcgi_src.c -o fastcgi_src -lfcgi
root@VM-0-16-ubuntu:/home/workplace/0voice_tuchuang/learn_test# ldconfig
root@VM-0-16-ubuntu:/home/workplace/0voice_tuchuang/learn_test# spawn-fcgi -a 127.0.0.1 -p 8001 -f ./fastcgi_src
spawn-fcgi: child spawned successfully: PID: 5926
root@VM-0-16-ubuntu:/home/workplace/0voice_tuchuang/learn_test# lsof -i:8001
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
fastcgi_s 5926 root 0u IPv4 15752309 0t0 TCP localhost:8001 (LISTEN)