Author: Kagula
发起日期:2014-11-08
最后更新日期:2016-02-29
环境:
[1]Win 8.1 64bits、 VMWare9,Cent OS 6.532bits, fcgid 2.3.9, boost 1.55, Apache 2.2.25,
[2] Cent OS 6.6,Apache 2.2.15, CMake 2.8.12.2, GCC 4.4.7, boost 1.57
Fast CGI相比CGI,响应速度提高了好几倍(免去了每次收到HTTP客户端请求,创建释放一次进程的开销),所以这里只记录Fast CGI的学习笔记。
Apache是一个后台运行的程序,没有界面。所有的配置,都包含在配置文件里。主配置文件是httpd.conf。
从官网下载httpd-2.2.25-win32-x86-openssl-0.9.8y.msi文件,选择自定义安装,勾选"Build Headers and Libraries"。这里假设默认路径安装。
Apache上有两种FastCGI模块,本文选择mod_fcgid。
加载mod_fcgid模块
从参考资料[7]下载mod_fcgid-2.3.9-crlf.zip文件,解压后用VisualStudio打开,为项目添加头文件search path
“C:\Program Files (x86)\Apache Software Foundation\Apache2.2\include”,
library path
" C:\Program Files (x86)\ApacheSoftware Foundation\Apache2.2\lib"
Release模式下编译出mod_fcgid.so文件后复制到”C:\Program Files (x86)\Apache Software Foundation\Apache2.2\modules “目录下。
在httpd.conf文件加入下面这行代码,加载fastcgi模块
LoadModule fcgid_module modules/mod_fcgid.so
装载新的module需要重启Apache服务器。
第一个程序,为了说明流程。
下载http://www.fastcgi.com/dist/fcgi.tar.gz,解压后编译。
新建项目
头文件搜索路径
“D:\SDK\fcgi-2.4.1-SNAP-0311112127\include”
库文件搜索路径
“D:\SDK\fcgi-2.4.1-SNAP-0311112127\libfcgi\Debug”
添加依赖库,libfcgi.lib
并把“libfcgi.dll”放在EXE输出所在路径上。
TestFastCGI.exe源文件清单如下:
#include <fcgi_stdio.h> int _tmain(int argc, _TCHAR* argv[]) { FCGX_Stream*in, *out, *err; FCGX_ParamArrayenvp; while(FCGX_Accept(&in, &out, &err, &envp) >= 0) { FCGX_PutS("content-type:text/plain\r\n\r\nHello World From FastCGI\r\n", out); } return0; }
源代码编译成功后(为了方便调试程序,这里使用DEBUG模式编译),输出到下面的路径中
D:\Workspace\TestFastCGI\Debug
现在这个路径下应该有下面两个文件
TestFastCGI.exe(编译输出文件)
libfcgi.dll(从fcgi工程中复制过来的动态库)
注意:FastCGI可执行程序所依赖的DLL(或则so)文件必须在同一个目录中。
修改Apache的 httpd.conf文件
添加下面的代码
LoadModule fcgid_module modules/mod_fcgid.so
... ...
<IfModule mod_fcgid.c>
<Directory "D:\Workspace\TestFastCGI\Debug">
SetHandler fcgid-script
Order allow,deny
Allow from all
</Directory>
ScriptAlias /myfcgid "D:\Workspace\TestFastCGI\Debug\TestFastCGI.exe"
IdleTimeout 3600
ProcessLifeTime 7200
MaxProcessCount 64
DefaultMaxClassProcessCount 8
IPCConnectTimeout 300
IPCCommTimeout 7200
BusyTimeout 300
</IfModule>
现在在浏览器中输入“localhost/myfcgid”就打印出了“HelloWorld From FastCGI”字符串。
我们看到/myfcgid路径被映射到了TestFastCGI.exe程序
Q:如何调试程序?
[S1]在任务管理器中停止Apache2.2服务。
[S2]调用“C:\Program Files(x86)\Apache Software Foundation\Apache2.2\bin\httpd.exe”启动Apache服务,现在可以找到程序“AttachProcess”了。
Q CentOS下FCGI程序没有对/www/var/fcgi-bin下的写权限.
把“fcgi-bin”目录的属主改为apache配置文件中apache的启动用户名,通常为“apache”或“www”。
例如用下面的命令:chown -R apache fcgi-bin
第二个程序,PUT/GET,Cookie,JSON
示例代码:
TestFastCGI.cpp(主程序)
/*! * \file TestFastCGI.cpp * \date 2014/11/09 20:47 * * \author kagula * Contact: [email protected] * * Fast CGI Demo */ #include <stdio.h> #include "FCGIHelper.h" int main(int argc, char* argv[]) { FCGX_Stream *in, *out, *err; FCGX_ParamArray envp; while (FCGX_Accept(&in, &out, &err, &envp) >= 0) { kagula::CFCGIHelper fcgi(in, out, err, envp); //first run, set cookie #ifdef WIN32 std::string strTest = fcgi.GetCookie("TEST"); #else //It's strange, difference from windows! std::string strTest = fcgi.GetCookie("TES"); #endif std::string strKagula = fcgi.GetCookie("kagula"); std::string strJSON = "=====>\r\n"; if (strTest.empty() == true) { fcgi.SetCookie("TEST", "first"); strJSON.append("Set Test Cookie!\r\n"); } if (strKagula.empty() == true) { fcgi.SetCookie("kagula", "second"); strJSON.append("Set kagula Cookie!\r\n"); } if (strTest.empty() == false && strKagula.empty() == false) { //if have cookies, output! strJSON.append("{\"TEST\",\""); strJSON.append(strTest); strJSON.append("\"},"); strJSON.append("{\"kagula\",\""); strJSON.append(strKagula); strJSON.append("\"}"); } fcgi.SetResponse(strJSON); }//end while return 0; }
FCGHelper.h
/*! * \file FCGIHelper.h * \date 2014/11/09 20:36 * * \author kagula * Contact: [email protected] * * Function: JSon Server Demo * * Support:POST/GET Method Request and return JSON object. */ #ifndef _CFGIHELPER_H_ #define _CFGIHELPER_H_ #include <map> #include <string> #include <fcgi_stdio.h> static const long MAX_BODY_LEN = 2*1024; namespace kagula { /* LastUpdateData: 2013-11-16 Test Environment [1]Win8.1, Visual Studio 2013 Update4, boost 1.55 [2]CentOS6.5, CMake 2.8.12.2, GCC 4.4.7 Reference [1]CGI Environment Variables http://www.cgi101.com/class/ch3/text.html */ class CFCGIHelper { public: CFCGIHelper(FCGX_Stream *in, FCGX_Stream *out, FCGX_Stream *err, FCGX_ParamArray &envp); ~CFCGIHelper(); bool IsGetRequest(); bool IsPOSTRequest(); void SetResponse(std::string strJSON); void SetCookie(std::string key, std::string value); std::string GetCookie(std::string key); std::map<std::string, std::string> _mapRequestData; private: std::string _strResponse; FCGX_Stream *_in; FCGX_Stream *_out; FCGX_Stream *_err; FCGX_ParamArray _envp; std::string _remoteIP; std::string _serverName; std::string _requestURI; std::string _requestMethod; std::string _queryString; std::string _contentType; std::string _contentLen; std::string _httpCookie; std::map<std::string, std::string> _mapCookieRead; std::map<std::string, std::string> _mapCookieWrite; void grab_envs(); void test_envs(); void extractFromBody(const char* inBuffer); void extractFromQueryString(); void Str2KeyValue(std::string strSrc, std::map<std::string, std::string> &mapKeyValue); std::string keyValue2Str(std::map<std::string, std::string> &mapKeyValue); }; } #endif
FCGHelper.cpp
/*! * \file FCGIHelper.cpp * \date 2014/11/09 20:48 * * \author kagula * Contact: [email protected] * * Support:POST/GET Method Request and return JSON object. */ #include "FCGIHelper.h" #include <algorithm> #include <vector> #include <boost/regex.hpp> #include <boost/algorithm/string.hpp> #pragma warning ( disable : 4129 ) namespace kagula { std::vector<std::string> split(std::string str, std::string pattern) { std::string::size_type pos; std::vector<std::string> result; str += pattern; std::string::size_type size = str.size(); for (unsigned int i = 0; i < size; i++) { pos = str.find(pattern, i); if (pos < size) { std::string s = str.substr(i, pos - i); result.push_back(s); i = pos + pattern.size() - 1; } } return result; } CFCGIHelper::CFCGIHelper(FCGX_Stream *in, FCGX_Stream *out, FCGX_Stream *err, FCGX_ParamArray &envp) { //initialization internal data _in = in; _out = out; _err = err; _envp = envp; //get environment grab_envs(); //extract query key-value char body[MAX_BODY_LEN]; memset(body, 0, sizeof(body)); if (IsPOSTRequest()) { FCGX_GetStr(body, sizeof(body), in); if (_contentType == "application/x-www-form-urlencoded" || _contentType == "application/x-url-encoded") { _queryString = (char *)&body; } else { extractFromBody(body); }//end if }//end if if (_queryString.empty() == false) { extractFromQueryString(); } Str2KeyValue(_httpCookie, _mapCookieRead); }//end func CFCGIHelper::~CFCGIHelper() { if (_strResponse.empty()) { test_envs(); } else { //define header! std::string body; if (_mapCookieWrite.size() > 0) { //define cookie if has! body = "Content-type: text/html; charset=UTF-8\r\n"; std::map<std::string, std::string>::iterator iterCookie = _mapCookieWrite.begin(); /* example: set-cookie:key=value:a:b; expires=Sun, 08-Jun-2014 14:27:09 GMT; path=/; domain=.domain.com\r\n set-cookie:key2=value2:a:b; expires=Sat, 08-Dec-2012 14:27:09 GMT; path=/; domain=.domain.com; HttpOnly\r\n\r\n */ while (iterCookie != _mapCookieWrite.end()) { std::string cookie = "Set-Cookie: "; cookie.append(iterCookie->first); cookie.append("="); cookie.append(iterCookie->second); cookie.append("\r\n"); body.append(cookie); iterCookie++; } /* indicate HTTP header is end. if no the "\r\n\r\n" flag, will throw out internal error! */ body.append("\r\n"); } else { body = "Content-type: application/json\r\n\r\n"; } body.append(_strResponse); FCGX_FPrintF(_out, "%s\r\n", body.c_str()); } } bool CFCGIHelper::IsGetRequest() { if (_requestMethod == "GET") return true; return false; } bool CFCGIHelper::IsPOSTRequest() { if (_requestMethod == "POST") return true; return false; } void CFCGIHelper::grab_envs() { _remoteIP = FCGX_GetParam("REMOTE_ADDR", _envp) == NULL ? "" : FCGX_GetParam("REMOTE_ADDR", _envp); _serverName = FCGX_GetParam("SERVER_NAME", _envp) == NULL ? "" : FCGX_GetParam("SERVER_NAME", _envp); _requestURI = FCGX_GetParam("REQUEST_URI", _envp) == NULL ? "" : FCGX_GetParam("REQUEST_URI", _envp); _requestMethod = FCGX_GetParam("REQUEST_METHOD", _envp) == NULL ? "" : FCGX_GetParam("REQUEST_METHOD", _envp); _requestMethod = _requestMethod.substr(_requestMethod.find_first_not_of(' '), _requestMethod.find_last_not_of(' ')); transform(_requestMethod.begin(), _requestMethod.end(), _requestMethod.begin(), toupper); _queryString = FCGX_GetParam("QUERY_STRING", _envp) == NULL ? "" : FCGX_GetParam("QUERY_STRING", _envp); _contentType = FCGX_GetParam("CONTENT_TYPE", _envp) == NULL ? "" : FCGX_GetParam("CONTENT_TYPE", _envp); _contentLen = FCGX_GetParam("CONTENT_LENGTH", _envp) == NULL ? "" : FCGX_GetParam("CONTENT_LENGTH", _envp); _httpCookie = FCGX_GetParam("HTTP_COOKIE", _envp) == NULL ? "" : FCGX_GetParam("HTTP_COOKIE", _envp); } void CFCGIHelper::test_envs() { FCGX_FPrintF(_out, "Content-type: text/plain\r\n\r\n"); FCGX_FPrintF(_out, "[CFCGIHelper Test Page]\r\n"); FCGX_FPrintF(_out, "REQUEST_URI: %s\r\n", _requestURI.c_str()); FCGX_FPrintF(_out, "REMOTE_ADDR: %s\r\n", _remoteIP.c_str()); FCGX_FPrintF(_out, "REQUEST_METHOD: %s\r\n", _requestMethod.c_str()); FCGX_FPrintF(_out, "SERVER_NAME: %s\r\n", _serverName.c_str()); FCGX_FPrintF(_out, "SERVER_PORT: %s\r\n", FCGX_GetParam("SERVER_PORT", _envp) == NULL ? "does not exist" : FCGX_GetParam("SERVER_PORT", _envp)); FCGX_FPrintF(_out, "SERVER_PROTOCOL: %s\r\n", FCGX_GetParam("SERVER_PROTOCOL", _envp) == NULL ? "is not exist" : FCGX_GetParam("SERVER_PROTOCOL", _envp)); FCGX_FPrintF(_out, "QUERY_STRING: %s\r\n", _queryString.c_str()); FCGX_FPrintF(_out, "keyValue2Str():\r\n%s\r\n", keyValue2Str(_mapRequestData).c_str()); } void CFCGIHelper::extractFromBody(const char* inBuffer) { std::vector<std::string> record; record = split(std::string(inBuffer), "------"); //Test Regular Expression//http://rubular.com/r/XY3EwbmdNH boost::regex reg("(?:[\\\s\\\S]*)Content-Disposition: form-data; name=\"(\\\w+)\"(?:[\\\s]*)(\\\w+)(?:[\\\s]*)"); for (std::string::size_type i = 0; i < record.size(); i++) { boost::cmatch cmat; //Remark: //boost::regex_match can extract string between left brace and right brace symbol! //boost::regex_match match the entire string! if (boost::regex_match(record[i].c_str(), cmat, reg) && cmat.size() == 3) { _mapRequestData[cmat[1]] = cmat[2]; } } } void CFCGIHelper::extractFromQueryString() { std::vector<std::string> record; boost::split(record, _queryString, boost::is_any_of("&")); for (std::string::size_type i = 0; i < record.size(); i++) { std::vector<std::string> kv; boost::split(kv, record[i], boost::is_any_of("=")); if (kv.size() == 2 && kv[0].size() > 0 && kv[1].size() > 0) { _mapRequestData[kv[0]] = kv[1]; } }//end for }//end func std::string CFCGIHelper::keyValue2Str(std::map<std::string, std::string> &mapKeyValue) { std::string strR; std::map<std::string, std::string>::iterator iter = mapKeyValue.begin(); while (iter != mapKeyValue.end()) { strR.append(iter->first); strR.append("="); strR.append(iter->second); strR.append("\r\n"); iter++; } return strR; } void CFCGIHelper::SetResponse(std::string strJSON) { _strResponse = strJSON; } std::string CFCGIHelper::GetCookie(std::string key) { if (_mapCookieRead.find(key) != _mapCookieRead.end()) { return _mapCookieRead[key]; } if (_mapCookieWrite.find(key) != _mapCookieWrite.end()) { return _mapCookieWrite[key]; } return std::string(); } void CFCGIHelper::SetCookie(std::string key, std::string value) { _mapCookieWrite[key] = value; _mapCookieRead[key] = value; } void CFCGIHelper::Str2KeyValue(std::string strSrc, std::map<std::string, std::string> &mapKeyValue) { std::vector<std::string> line; boost::split(line, strSrc, boost::is_any_of(";")); for (unsigned int i = 0; i < line.size(); i++) { std::vector<std::string> vecT; boost::split(vecT, line[i], boost::is_any_of("=")); if (vecT.size() == 2) { vecT[0] = vecT[0].substr(vecT[0].find_first_not_of(' '), vecT[0].find_last_not_of(' ')); mapKeyValue[vecT[0]] = vecT[1]; }//end if }//end for } }//end class
HTMLPage.h
#ifndef _CHTMLPage_H_ #define _CHTMLPage_H_ #ifdef WIN32 #pragma once #endif // WIN32 #include <fcgi_stdio.h> namespace kagula { //https://github.com/einsteinx2/WaveBoxUrlRedirector/blob/master/wavebox_url_redirector.c class CHTMLPage { public: // Send the not found header, used for unregistered URLs void not_found(FCGX_Stream* out); // Send the not implemented header, used for request types other // than GET and POST void unimplemented(FCGX_Stream* out); }; } #endif
HTMLPage.cpp
#include "HTMLPage.h" namespace kagula { // Send the not found header, used for unregistered URLs void CHTMLPage::not_found(FCGX_Stream* out) { FCGX_FPrintF(out, "Status: 404 Not Found\r\n" "Content-type: text/html\r\n" "\r\n"); } // Send the not implemented header, used for request types other // than GET and POST void CHTMLPage::unimplemented(FCGX_Stream* out) { FCGX_FPrintF(out, "Status: 501 Method Not Implemented\r\n" "Allow: GET, POST\r\n" "Content-type: text/html\r\n" "\r\n"); } }
我们的程序依赖boost库,在centOS上安装boost之前建议使用
yum install libicu libicu-devel zlib zlib-develpython-devel bzip2-devel texinfo gcc-c++
安装ICU等依赖项,然后参考资料[14]进行安装。
在LInux上安装FCGI
[S1]下载FCGI包
wget http://www.fastcgi.com/dist/fcgi.tar.gz
[S2]参考下面的URL
http://redmine.lighttpd.net/projects/spawn-fcgi/wiki/Build
用第一次方法安装FCGI。可能会碰到EOF未定义的问题, 给报错的cpp文件加一个就可以了。
[S3]
默认头文件路径"/usr/include"
默认库文件路径"/usr/lib"
在这个路径下可以看到"libfcgi.a","libfcgi.so"文件或链接.
下面是CMakeLists.txt清单
#设置项目名称 project(TestFastCGI) #要求CMake的最低版本为2.8 cmake_minimum_required(VERSION 2.8) #For Boost library add_definitions(-DBOOST_ALL_NO_LIB) set(Boost_USE_STATIC_LIBS OFF) # using dynamic files set(Boost_USE_MULTITHREADED ON) set(Boost_USE_STATIC_RUNTIME OFF) find_package(Boost 1.55 COMPONENTS regex REQUIRED) include_directories(${Boost_INCLUDE_DIRS}) #For FCGI library set(FCGI_INCLUDE_DIRS /usr/include/) set(FCGI_LIBRARY_DIRS /usr/lib/) include_directories(${FCGI_INCLUDE_DIRS}) #用于将当前目录下的所有源文件的名字保存在变量 DIR_SRCS 中 aux_source_directory(. DIR_SRCS) #用于指定从一组源文件 source1 source2 … sourceN(在变量DIR_SRCS中定义) #编译出一个可执行文件且命名为CMake_Tutorial1 add_executable(TestFastCGI ${DIR_SRCS}) #We need some third party libraries to run our program! target_link_libraries(TestFastCGI ${Boost_LIBRARIES} fcgi)
我们可以查找CMake FindBoost的帮助,命令如下
cmake --help-module FindBoost
把包含cpp文件的目录上传到Cent OS后。
切换到Cent OS
在包换TestFastCGI.cpp的目录下,建立build子目录,使用下面的
cmake ..
make
编译出名为TestFastCGI可执行程序。
现在使用“./TestFastCGI”命令,可以正常运行,接下去配置到Apache上。
为Cent OS Apache配置mod_fcgid模块
下载mod_fcgid-2.3.9.tar.gz文件,解压后会看到
configure.apxs可执行文件,使用下面的命令编译并安装。
yum install httpd-devel
./configure.apxs
make
make install
chmod 755 /var/log/httpd #For log out
现在httpd.conf文件中已经加入了下面的代码
LoadModule fcgid_module/usr/lib/httpd/modules/mod_fcgid.so
通过下面的命令新建fcgid.conf文件
# vi /etc/httpd/conf.d/fcgid.conf
添加下面的内容
<IfModule mod_fcgid.c>
FcgidIPCDir /var/run/mod_fcgid
FcgidProcessTableFile /var/run/mod_fcgid/fcgid_shm
AddHandler fcgid-script .fcgi
SocketPath /tmp/fcgid_sock/
IPCConnectTimeout 20
MaxProcessCount 8
DefaultMaxClassProcessCount 2
TerminationScore 10
SpawnScore 80
IdleTimeout 300
</IfModule>
确保/var/run/mod_fcgid目录存在,而且属主改为apache。
如果启动Apache失败,报“httpd dead but subsys locked”错误,可尝试使用下面的命令调试。
ipcs -s | grep apache | perl -e 'while (<STDIN>) {@a=split(/\s+/); print `ipcrm sem $a[1]`}'
rm -f /var/lock/subsys/httpd
rm -f /var/log/httpd/error_log
service httpd start
cat /var/log/httpd/error_log
如果/var/run/mod_fcgid不存在,就是用下面的命令
#mkdir /var/run/mod_fcgid
#chown apache /var/run/mod_fcgid
现在有了这个目录,而且属主已经改为apache。
在/var/www目录下新建fcgi-bin目录
把TestFastCGI及其依赖的so文件复制到fcgi-bin目录,否则/usr/bin/ld不能找到动态链接库。
我们的TestFastCGI只依赖libfcgi.so文件,所以我们也要把它复制到fcgi-bin目录。
我喜欢把网站要用到的文件全部放到/var/www/目录,避免时间花在权限调整上面。
在httpd.conf下添加下面的设置(除了目录名称和文件名称不同,其它同Windows)
<IfModule mod_fcgid.c>
<Directory "/var/www/fcgi-bin">
SetHandler fcgid-script
Order allow,deny
Allow from all
</Directory>
ScriptAlias /myfcgid "/var/www/fcgi-bin/TestFastCGI"
IdleTimeout 3600
ProcessLifeTime 7200
MaxProcessCount 64
DefaultMaxClassProcessCount 8
IPCConnectTimeout 300
IPCCommTimeout 7200
BusyTimeout 300
</IfModule>
保存后退出重启Apache
#service httpd restart
然后通过“http://192.168.19.130/myfcgid”网址就可以访问了,其中“192.168.19.130”是我Cent OS机器的IP地址。
为了方便在Cent OS上调试我们的FastCGI程序,我们可以新建Shell脚本,示例代码如下
# vi rebuild.sh
#!/bin/sh
service httpd stop
make clean
make
mv TestFastCGI /var/www/fcgi-bin
service httpd start
#chmod 755 rebuild.sh
附:
Win8下通过启用CGI查看Apache服务器环境
修改“C:\ProgramFiles (x86)\Apache Software Foundation\Apache2.2\conf”路径下的httpd.conf文件,原
<Directory "C:/Program Files (x86)/Apache SoftwareFoundation/Apache2.2/cgi-bin">
AllowOverride None
Options None
Order allow,deny
Allow from all
</Directory>
改为
<Directory "C:/Program Files (x86)/Apache SoftwareFoundation/Apache2.2/cgi-bin">
AllowOverride None
Options ExecCGI
Order allow,deny
Allow from all
</Directory>
打开任务管理器->服务->Apache2.2->重启服务
在浏览器中输入下面的地址(前提是启用了CGI)
http://127.0.0.1/cgi-bin/printenv.pl
打印当前环境变量
修改侦听端口
Listen 80
查看网站根目录在哪里
DocumentRoot"C:/Program Files (x86)/Apache Software Foundation/Apache2.2/htdocs"
配置虚拟目录
找到<IfModule alias_module>节点,在这个节点下可以配置虚拟目录
例如可以插入下面的代码段
Alias /vdir1 "D:/wwwroot/mydir1"
<Directory "D:/wwwroot/ mydir1">
Options Indexes FollowSymLinks MultiViews
AllowOverride None
order allow,deny
Allow from all
</Directory>
[1]Apache HTTP Server Project(Apache HTTPD)
http://httpd.apache.org/
[2]Apache HTTP Server Version 2.2Documentation
http://httpd.apache.org/docs/2.2/en/
[3] windows下apache设置域名创建虚拟目录
http://www.crackedzone.com/apache-domain-virtual-directory.html
[4] Apache与Tomcat整合
http://www.cnblogs.com/itech/archive/2009/08/18/1548723.html
http://zhidao.baidu.com/link?url=_aaTUHghrT0MxMnEx9iDFkNHdye5QisbwAEW1D2GJBtDN-Vm8pjzVHPlqn7qekdwpnXPeH74-pgOAc7q_2zslK
[5] [Apache手册]Linux环境下配置Apache运行cgi
http://blog.snsgou.com/post-686.html
[6] fastcgi与cgi的区别
http://www.cnblogs.com/lmule/archive/2010/12/09/1900914.html
[7]Apache fcgid模块
http://httpd.apache.org/download.cgi#mod_fcgid
[8]Apache and FastCGI
https://wiki.archlinux.org/index.php/Apache_and_FastCGI
[9]How to create a cookie with fastcginginx in c
http://stackoverflow.com/questions/15722795/how-to-create-a-cookie-with-fastcgi-nginx-in-c
[10]about return JSON
https://github.com/einsteinx2/WaveBoxUrlRedirector/blob/master/wavebox_url_redirector.c
[11] Configuring and Building Boost withCMake
https://svn.boost.org/trac/boost/wiki/CMakeConfigAndBuild
[12] Running Movable Type with FastCGI
https://movabletype.org/documentation/administrator/maintenance/fastcgi.html
[13] Apache does not start: No such file ordirectory: mod_fcgid: Can't create shared memory for size
http://kb.sp.parallels.com/en/121494
[14] Compiling and Installing Boost C++Libraries on CentOS
http://linuxtoolkit.blogspot.com/2012/11/compiling-and-installing-boost-c.html
[15] Apache permission denied
http://stackoverflow.com/questions/11992466/apache-permission-denied
[16]Apache fcgid 配置参数
http://httpd.apache.org/mod_fcgid/mod/mod_fcgid.html
[1]这里只是介绍,实际开发还会遇到很多问题需要解决。
http://www.fastcgi.com/dist/fcgi.tar.gz文件中有很多例子,比如说echo程序,可以打印当前FastCGI程序的环境变量等,这里例子里的代码可以借鉴。
[2]访问fcgi很慢,CentOS+Apache下总是返回空字符串。
查询/var/log/httpd下的Apache日志,看到“mod_fcgid: can't apply process slot for”错误信息。
[2-1]
FcgidMaxProcessesPerClass(即DefaultMaxClassProcessCount的设置)
指的是你的一个fcgi程序最多能派生出几个进程,如果超过这个限制,会提示
mod_fcgid: can't apply process slot for 错误信息。
[2-2]
使用top命令发现Zombie进程达到DefaultMaxClassProcessCount设置上限。
这个参数我一般在apache中设置为8.
[2-3]
查询zombie进程,第一列是进程号。
ps -A -ostat,ppid,pid,cmd | grep -e '^[Zz]'
[2-4-final]
杀掉Zombie进程后,Apache恢复正常fcgi请求响应。
[3]CentOS7+Apache2.4中,fcgi程序的典型设置
<IfModule mod_fcgid.c> <Directory "/var/www/fcgi-bin"> SetHandler fcgid-script Order allow,deny Allow from all </Directory> ScriptAlias /plate/detection/detect "/var/www/fcgi-bin/fcgi_plate_recognition" FcgidIdleTimeout 600 FcgidProcessLifeTime 3600 FcgidMaxProcesses 512 #每个fcgi程序可以衍生出最多128个进程 FcgidMaxProcessesPerClass 128 FcgidConnectTimeout 10 FcgidIOTimeout 60 FcgidBusyTimeout 300 </IfModule>