fastCGI研究记录
来源:互联网 发布:鸡蛋进口数据2015 编辑:程序博客网 时间:2024/06/01 19:46
本来构思的OJ是在将前端放在虚拟空间上,在自己的机器上开Judge服务,通过动态DNS来连接。可是自己电脑就得一直开着,不好办。最后还是想租一台主机,如果经济不允许的话就买个便宜的VPS。可是VPS最大的问题是内存一超就死机。特别是运行JVM之类特别消耗内在的进程。而且OJ也只是一个CMS,前端主要处理数据的显示,没有过多复杂的业务逻辑,也不需要复杂的关系模型。为了简化应用的架构,打算采用C/C++来编写前台和后台,将它们都放在VPS上运行。
用C/C++来写Web应用,想到就是CGI,可是CGI的性能和效率也不好,特别是处理并发的时候。虽然不热门的OJ访问量不会很大,但为了给以后有一点点的扩展空间,还是希望它支持并发,至少也可以多线程处理请求。便选择了fastCGI。
fastCGI并不是什么新技术,上个世纪已出现,而且很多企业都多得很成熟,特别是在电信业和要求信息处理效率比较高的行业中使用很广泛。因为程序都是编译成本地代码,执行的效率要比Java,.NET,PHP等都高点,而且占用的资源可以更加少。应用的结构也比较简单所以编程的难度也不高,只要开发前做一个整体设计,把模块分清楚,要使用类似MVC的模型也完全可以做到。
在fastCGI里的开发库里(可以在http://www.fastcgi.com/drupal/node/5下载),有两种API可以使用,一种是包含头文件“fcgi_stdio.h”,可以直接通过标准输出流进行response数据的输出;而另一个“fcgiapp.h”则通过自身的特定函数来输出数据。我选择后者,因为前者在使用时一定要保证在程序中引用的库里都没有“stdio.h”,否则容易出现IO错误。而且前者也不支持多线程,所以只能选择后者了。下面的内容都是使用“fcgiapp.h”。
fastCGI程序的一般模式就是一个请求循环,因为fastCGI需要有守护进程,程序执行之后就像服务一样,一直在等待请求,处理请求,返回response,然后又等待请求……如此一直循环,循环体就类似于。
while (FCGX_Accept(&in, &out, &err, &envp) >= 0) { char *contentLength = FCGX_GetParam("CONTENT_LENGTH", envp); int len = 0; FCGX_FPrintF(out, "Content-type: text/htmlrn" "rn" "<title>FastCGI echo (fcgiapp version)</title>" "<h1>FastCGI echo (fcgiapp version)</h1>n" "Request number %d, Process ID: %d<p>n", ++count, getpid());} /* while */
但是上面的倒子没法处理多线程,下面是我在Windows环境下写的可以处理多线程的fastCGI的例子。例子中使用了互斥锁,对一个计数器进行累加,避免多线程同时读写同一个资源而导致数据出错或不同步。
#include <windows.h> #include "fcgi/fcgi_config.h"#include "fcgi/fcgiapp.h"#pragma comment(lib, "libfcgi.lib") #define THREAD_COUNT 20 DWORD WINAPI foo(LPVOID params);static void PrintEnv(FCGX_Stream *out, char *label, char **envp); static HANDLE accept_mutex = CreateMutex(NULL, FALSE, NULL);static HANDLE count_mutex = CreateMutex(NULL, FALSE, NULL); static int count = 0; int _tmain(int argc, _TCHAR* argv[]) { HANDLE tid[THREAD_COUNT]; FCGX_Init(); for (int i = 1; i < THREAD_COUNT; i++) { tid[i] = CreateThread(NULL, 0, foo, (LPVOID) i, 0, NULL); } foo(0); return 0;} static void PrintEnv(FCGX_Stream *out, char *label, char **envp) { FCGX_FPrintF(out, "%s:<br>n<pre>n", label); for( ; *envp != NULL; envp++) { FCGX_FPrintF(out, "%sn", *envp); } FCGX_FPrintF(out, "</pre><p>n");} DWORD WINAPI foo(LPVOID params) { int rc; FCGX_Request request; FCGX_InitRequest(&request, 0, 0); char* server_name; int tid = (int) params; unsigned long id = GetCurrentThreadId(); while (1) { WaitForSingleObject(accept_mutex, INFINITE); rc = FCGX_Accept_r(&request); ReleaseMutex(accept_mutex); if (rc < 0) { break; } server_name = FCGX_GetParam("SERVER_NAME", request.envp); FCGX_FPrintF(request.out, "Content-type: text/htmlrn" "rn" "<h1>" "THREAD_ID: %d<br/>" "CurrentThreadId: %u<br/>" "Server Name: %s<br/>" "</h1>", tid, id, server_name ? server_name : "?"); Sleep(2); WaitForSingleObject(count_mutex, INFINITE); ++count; FCGX_FPrintF(request.out, "%d<br/>", count); ReleaseMutex(count_mutex); PrintEnv(request.out, "Request environment", request.envp); PrintEnv(request.out, "Initial environment", environ); FCGX_Finish_r(&request); } return 0;}
经过适当的封装和改造就可以变成一个控制器。
要运行fastCGI程序,首先要有一个支持fastCGI反向代理的服务器,如Apache,Nginx,Lighttpd等。能够支持fastCGI的服务器的详细列表可以查看http://www.fastcgi.com/drupal/node/3。
但是有服务器的支持还不够,因为fastCGI需要作为守护进程来运行才可以正常被访问。因此还需要将编译好的fastCGI程序绑定到指定的端口,并一直监听才行。而能够完成这项工作的工具可以选择fastCGI开发库中的cgi-fcgi程序,该程序只提供源代码,可以在Windows和Unix环境下编译,编译的时候注意去掉不属性编译环境下的头文件,以避免出现找不到头文件的编译错误。如在Windows下编译,就应该去掉包括sys/param.h,sys/time.h和unistd.h。在编译时还得上libfcgi.lib。
其实lighttpd项目也有一个类似的程序spawn-fcgi,也可以在Windows和Unix下平台编译运行。关于cgi-fcgi和spawn-fcgi在Linux下的使用可以查看http://stackoverflow.com/questions/2149709/c-language-fastcgi-with-nginx。
发现上面链接中说明的方法在Windows下有所不同。可以是不同系统对套接口支持的差异。下面是在Windows下,使用Nginx服务器来启动fastCGI的方法。
首先配置Nginx,在nginx.conf文件中加入下面的配置参数,就是将前缀为“http://host/cgi-bin”的请求反向代理到9000端口进行处理:
location /cgi-bin { fastcgi_pass 127.0.0.1:9000; include fastcgi_params; }然后启动Nginx服务进程,在运行下面的命令即可启动fastCGI程序
cgi-fcgi -start -connect localhost:9000 testcgi.exe
通过浏览器访问http://host/cgi-bin,即fastCGI程序进行请求
- fastCGI研究记录
- IIS7.5+FastCGI+PHP设置记录
- FastCGI
- FastCGI
- fastcgi
- fastcgi
- fastcgi
- fastcgi
- fastcgi
- FastCGI
- FastCGI
- FastCGI
- FastCGI
- FastCGI
- FastCGI
- FastCGI
- 记录研究历程
- Android研究记录
- PHP natsort 用“自然排序”算法对数组排序
- 【面向代码】学习 Deep Learning(一)Neural Network
- Postback 之后保持浏览器滚动条的位置
- 打印数字图形
- android下Cocos2d-x 编译
- fastCGI研究记录
- 针对insert into update 的理解 深刻入理 sqlite3
- asp.net ajax 的几种操作方法
- Spring学习之——依赖关系和配置细节(二)
- VS2012中 C++创建DLL图解
- android service后台服务生命周期与常驻后台
- hdu——1081(二维最大连续和)
- 通讯录里面的通讯源
- 例7.9 输入10个数,要求输出其中值最大的元素和该数是第几个数。