1.介绍
高性能web server。
程序 - 常驻型CGI(Common Gateway Interface)程序,它是语言无关的、可伸缩架构的CGI开放扩展,其主要行为是将CGI解释器进程保持在内存中并因此获得较高的性能。
要调用FastCGI程序,需要用到FastCGI的进程管理器,Nginx本身没有集成类似的模块,我们可以使用lighttpd中的spawn-fastcgi。(也可安装nginx-fcgi来让nginx支持fast cgi)。
FastCGI接口在Linux下是socket(这个socket可以是文件socket,也可以是ip socket)。当Nginx将CGI请求发送给这个socket的时候,通过FastCGI接口,wrapper接收到请求,然后派生出一个新的线程,这个线程调用解释器或者外部程序处理脚本并读取返回数据;接着,wrapper再将返回的数据通过FastCGI接口,沿着固定的socket传递给Nginx;最后,Nginx将返回的数据发送给客户端。这就是Nginx+FastCGI的整个运作过程,如图1所示。
图1 Nginx+FastCGI运行过程
接口方式在脚本解析服务器(CGI应用程序服务器)上启动一个或者多个守护进程对动态脚本进行解析,这些进程就是FastCGI进程管理器,或者称为FastCGI引擎。 spawn-fcgi与PHP-FPM都是FastCGI进程管理器(分别支持C/C++和PHP)。
2.准备工作
2.1.Nginx(这里我使用的是tengine)的安装、部署与配置
安装]
./configure --prefix=${TENGINE_INSTALL_DIR} --with-openssl=${OPENSSL_SRC_DIR} --with-pcre=${PCRE_SRC_DIR} --group=www --user=www --with-http_stub_status_module --with-http_ssl_module
make
make install
[配置和管理]
1)添加www用户组和用户www:
sudo /usr/sbin/groupadd -f www; sudo /usr/sbin/useradd -g www www
2)执行选项
为 Nginx 指定一个配置文件,来代替缺省的。不输入则使用默认的配置文件。
不运行,而仅仅测试配置文件。nginx 将检查配置文件的语法的正确性,并尝试打开配置文件中所引用到的文件。
显示 nginx 的版本。
显示 nginx 的版本,编译器版本和配置参数。
3)启动 - 默认和特殊
${TENGINE_INSTALL_DIR}/sbin/nginx (默认启动方式)
${TENGINE_INSTALL_DIR}/sbin/nginx -c ${TENGINE_INSTALL_DIR}/conf/nginx.conf (指定配置文件启动)
4)查看nginx进程号(master是主进程)
ps -ef | grep nginx
5)重新加载配置文件
sudo kill -HUP [nginx主进程号] 或者 sudo nginx -s reload
6) 通过系统的信号控制 Nginx
可以使用信号系统来控制主进程。默认,nginx 将其主进程的 pid 写入到 ${TENGINE_INSTALL_DIR}/logs/nginx.pid 文件中。
主进程可以处理以下的信号:
命令 说明 备注
快速关闭
从容关闭
重载配置 用新的配置开始新的工作进程 从容关闭旧的工作进程
重新打开日志文件
平滑升级可执行程序
从容关闭工作进程
7)默认目录结构
主目录:${TENGINE_INSTALL_DIR}/
配置目录:${TENGINE_INSTALL_DIR}/conf/
root目录:${TENGINE_INSTALL_DIR}/html/
可执行文件路径:${TENGINE_INSTALL_DIR}/sbin/
2.2.spawn_fastcgi的安装、部署与配置
地址https://github.com/lighttpd/spawn-fcgi
./autogen.sh
./configure --prefix=${SPAWN_FCGI_INSTALL_DIR}
make
sudo cp -f ./src/spawn-fcgi ${TENGINE_INSTALL_DIR}/sbin/
2.3.fastcgi库的安装
地址 http://www.fastcgi.com/dist/fcgi.tar.gz
解压后,在/include/fcgio.h文件中加上 #include <cstdio>
./configure --prefix=${FCGI_INSTALL_DIR}
make
make install
3.fcgi_emo和web发布
3.1.fcgi_demo程序
#include <stdlib.h>
#include <iostream>
#include "fcgio.h"
using namespace std;
// Maximum bytes
const unsigned long STDIN_MAX = 1000000;
/**
* Note this is not thread safe due to the static allocation of the
* content_buffer.
*/
string get_request_content(const FCGX_Request& request)
{
char* content_length_str = FCGX_GetParam("CONTENT_LENGTH", request.envp);
unsigned long content_length = STDIN_MAX;
if (content_length_str)
{
content_length = strtol(content_length_str, &content_length_str, 10);
if (*content_length_str)
{
cerr << "Can't Parse 'CONTENT_LENGTH='"
<< FCGX_GetParam("CONTENT_LENGTH", request.envp)
<< "'. Consuming stdin up to " << STDIN_MAX << endl;
}
if (content_length > STDIN_MAX)
{
content_length = STDIN_MAX;
}
}
else
{
// Do not read from stdin if CONTENT_LENGTH is missing
content_length = 0;
}
char* content_buffer = new char[content_length];
cin.read(content_buffer, content_length);
content_length = cin.gcount();
// Chew up any remaining stdin - this shouldn't be necessary
// but is because mod_fastcgi doesn't handle it correctly.
// ignore() doesn't set the eof bit in some versions of glibc++
// so use gcount() instead of eof()...
do cin.ignore(1024); while (cin.gcount() == 1024);
string content(content_buffer, content_length);
delete[] content_buffer;
return content;
}
int main(void)
{
// Backup the stdio streambufs
streambuf* cin_streambuf = cin.rdbuf();
streambuf* cout_streambuf = cout.rdbuf();
streambuf* cerr_streambuf = cerr.rdbuf();
FCGX_Request request;
FCGX_Init();
FCGX_InitRequest(&request, 0, 0);
while (FCGX_Accept_r(&request) == 0)
{
fcgi_streambuf cin_fcgi_streambuf(request.in);
fcgi_streambuf cout_fcgi_streambuf(request.out);
fcgi_streambuf cerr_fcgi_streambuf(request.err);
cin.rdbuf(&cin_fcgi_streambuf);
cout.rdbuf(&cout_fcgi_streambuf);
cerr.rdbuf(&cerr_fcgi_streambuf);
const char* uri = FCGX_GetParam("REQUEST_URI", request.envp);
string content = get_request_content(request);
if (content.length() == 0)
{
content = ", World!";
}
cout << "Content-type: text/html\r\n"
<< "\r\n"
<< "<html>\n"
<< " <head>\n"
<< " <title>Hello, World!</title>\n"
<< " </head>\n"
<< " <body>\n"
<< " <h1>Hello " << content << " from " << uri << " !</h1>\n"
<< " </body>\n"
<< "</html>\n";
// Note: the fcgi_streambuf destructor will auto flush
}
// restore stdio streambufs
cin.rdbuf(cin_streambuf);
cout.rdbuf(cout_streambuf);
cerr.rdbuf(cerr_streambuf);
return 0;
}
编译]
3.2.web发布
1)将CGI可执行程序fcgi_demo移动到nginx的安装目录下 ${TENGINE_INSTALL_DIR}/cgibin (文件夹不存在则自己创建)
)启动spawn-fcgi管理进程,并绑定server IP和端口(不要跟nginx的监听端口重合)
${TENGINE_INSTALL_DIR}/sbin/spawn-fcgi -a 127.0.0.1 -p 8088 -F 10 ${TENGINE_INSTALL_DIR}/cgibin/fcgi_demo
注意上面是一行。
查看选项含义:/spawn-fcgi -h】
查看一下8088端口是否已成功:netstat -na | grep 8088
3)更改nginx.conf配置文件,让nginx转发请求,注意先备份nginx.conf。
在http节点的子节点-"server节"点中下添加配置
rewrite /api1 /fcgi_demo.cgi break;
rewrite /api2 /fcgi_demo.cgi break;
location ~ \.cgi$ {
fastcgi_pass 127.0.0.1:8088;
fastcgi_index index.cgi;
fastcgi_param SCRIPT_FILENAME fcgi$fastcgi_script_name;
include fastcgi_params;
}
}
可选配置:
fastcgi_param GATEWAY_INTERFACE CGI/1.1;
fastcgi_param SERVER_SOFTWARE nginx;
fastcgi_param QUERY_STRING $query_string;
fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param CONTENT_TYPE $content_type;
fastcgi_param CONTENT_LENGTH $content_length;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_param REQUEST_URI $request_uri;
fastcgi_param DOCUMENT_URI $document_uri;
fastcgi_param DOCUMENT_ROOT $document_root;
fastcgi_param SERVER_PROTOCOL $server_protocol;
fastcgi_param REMOTE_ADDR $remote_addr;
fastcgi_param REMOTE_PORT $remote_port;
fastcgi_param SERVER_ADDR $server_addr;
fastcgi_param SERVER_PORT $server_port;
fastcgi_param SERVER_NAME $server_name;
4)重启nginx或者重新加载配置文件
sudo ./nginx -s reload
5)打开浏览器访问一下吧
http://localhost/api1
或者:curl -d "chris" http://localhost/api1