fastCGI研究記錄
本來構思的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程式進行請求
相關文章
- nginx fastcgi 超時問題解決記錄NginxAST
- 記錄一個 Nginx-FastCGI-"Primary script unknown" 錯誤NginxAST
- fastcgi配置AST
- CGI與FastCGIAST
- FastCGI規範AST
- CGI和FastCGIAST
- Nginx配置fastcgi cacheNginxAST
- Nginx 配置 fastcgi cacheNginxAST
- FastCGI協議分析AST協議
- nginx結合fastcgiNginxAST
- PHP FastCGI RCE VulPHPAST
- PUTTY 記錄操作記錄
- 域名解析的記錄型別:A記錄、CNAME、MX記錄、NS記錄型別
- cgi,fastcgi,php-fpmASTPHP
- apache-實戰FastCGIApacheAST
- Cookie記錄瀏覽記錄Cookie
- Xshell 5 記錄操作記錄
- PHP fastcgi_finish_request 方法PHPAST
- 記錄
- 研究大事記(部分)
- 淘寶記錄筆記筆記
- 寫了一個 FastCGI 實現AST
- CGI / FASTCGI已停止工作 彩蛋?AST
- FastCGI 程式管理器(FPM)-配置AST
- fastcgi協議分析與例項AST協議
- Linux 目錄許可權研究Linux
- 面試記錄面試
- Git記錄Git
- 命令記錄
- 工具記錄
- 地址記錄
- 機器學習記錄機器學習
- explain記錄AI
- GitText記錄Git
- 思路記錄
- git 記錄Git
- 照片記錄
- Kafka 記錄Kafka