Apache Fast CGI C++程序开发

Apache Fast CGI开发

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

Windows 8平台

         从官网下载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");
	}
}

移植到CentOS

    我们的程序依赖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>




具体原因参考下面的URL
http://stackoverflow.com/questions/18680949/high-cpu-mod-fcgid-cant-apply-process-slot




你可能感兴趣的:(Apache Fast CGI C++程序开发)