1.lighttpd 服务器
lighttpd是一个比较轻量的服务器,在运行fastcgi上效率较高。lighttpd只负责投递请求到fastcgi。
centos输入yum install lighttpd安装
2.fastcgi
fastcgi解决了cgi程序处理请求每次都要初始化和结束造成的性能问题。fastcgi并且是独立于webserver的,fastcgi的crash并不影响webserver,然后他们之间通过soket通信。与fastcgi不同的另一种解决cgi程序反复创建,销毁的方法是让webserver开放api,然后编写cgi的时候,把cgi嵌入到webserver中,这样有个不好的地方就是cgi的crash会影响到webserver。
支持fastcgi的服务器有很多比如,nginx IIS什么的。他们都是把http请求转换为stdin和一些环境变量传递给fastcgi程序,然后返回stdout。编写fastcgi程序最终要的一个api就是int FCGI_Accept(void);当一个请求被送达的时候返回。一个基本的fastcgi结构如下。
echo.c
#include "fcgi_stdio.h" #include <stdlib.h> void main(void) { //初始化一些全局变量,这里只在fastcgi启动时候运行一次 while(FCGI_Accept() >= 0) { //fastcgi的处理逻辑 //根据http协议返回处理结果 printf("Content-type: text/html\r\n"); printf("\r\n"); printf("hello world"); } }
3.编译echo.c
编译时候首先要安装fastcti
wget http://www.fastcgi.com/dist/fcgi.tar.gz
tar -zxvf fcgi.tar.gz
cd fcgi-2.4.1-SNAP-0311112127/
./configure --prefix=/etc/fcgi
make && make install
出现fcgio.cpp:50: error: 'EOF' was not declared in this scope的话 在/include/fcgio.h文件中加上 #include <cstdio>
到此就安装完了。然后我们来编译echo.c
gcc echo.c -o echo.cgi -I/etc/fcgi/include -L/etc/fcgi/lib/ -lfcgi
注意-I -L -l都不能少。
4.lighttpd+fastcgi配置
lighttpd支持fastcgi需要安装fastcgi模块
yum install lighttpd-fastcgi
创建配置文件 vim /etc/fcgi/fcgi.conf
server.document-root = "/var/www/cgi-bin/"
server.port = 8080
server.username = "www-data"
server.groupname = "www-data"
server.modules = ("mod_access", "mod_accesslog", "mod_fastcgi")
server.errorlog = "/var/www/cgi-bin/error.log"
accesslog.filename = "/var/www/cgi-bin/access.log"
static-file.exclude-extensions = (".cgi" )
fastcgi.debug = 1
fastcgi.server = (
"echo.cgi" => ((
"host" => "127.0.0.1",
"port" => "9000",
"bin-path" => "/var/www/cgi-bin/echo.cgi",
))
)
lighttpd -D -f fcgi.conf 时候会出现error while loading shared libraries: libfcgi.so.0: cannot open shared object file: No such file or directory
反正就是找不到动态链接库,比较无脑的方式就是把fastcgi安装目录下的include和lib都拷贝到/usr/include 和 /usr/lib中。注意,不是/usr/local
设置过之后可能还是找不到,参考网上另一种方法是。
首先vim /etc/ld.so.conf 添加libfcgi.so.0的路径,然后运行/sbin/ldconfig,重新编译trie.cgi,ldd trie.cgi一下,看到libfcgi.so.0找到就OKAY了。
在浏览器输入http://127.0.0.1:8080/echo.cgi 就可以看到hello world了
5.实例 输入提示
输入提示的具体实现方法已经在这篇博客里说过 http://www.cnblogs.com/23lalala/p/3513492.html
这次把他通过fastcgi的api改写成fastcgi程序。
trie.c
#include "stdio.h" #include "stdlib.h" #include "string.h" #include "malloc.h" #include "fcgi_stdio.h" char* strcatch(char *str, char ch) { char *p = str; while (*p!='\0') { p++; } *p = ch; *(p+1) = '\0'; return str; } #define MAX_NODE 100000 #define ALPHA_COUNT 128 typedef struct t_trie{ int ch[MAX_NODE][ALPHA_COUNT]; int val[MAX_NODE]; int size; }trie; trie* create() { trie *root = (trie *)malloc(sizeof(trie)); root->size = 1; memset(root->ch[0], 0, sizeof(root->ch[0])); return root; } void insert(trie *root, char *str, int n) { int i, cur = 0, pre = cur; for (i=0; i<n; i++) { int c = str[i]-'\0'; if (!root->ch[cur][c]) { memset(root->ch[root->size], 0, sizeof(root->ch[root->size])); root->val[root->size] = 0; root->ch[cur][c] = root->size++; } cur = root->ch[cur][c]; } root->val[cur] = 1; } int search(trie *root, char *str) { int i, cur = 0, n = strlen(str); for (i=0; i<n; i++) { int c = str[i]-'\0'; cur = root->ch[cur][c]; } if (root->val[cur]) { return 1; } return 0; } void suggest_helper(trie *root, char* str, int cur, int i, int *count) { if (*count > 9) { return; } if (root->val[cur]) { *count = *count+1; char c = i+'\0'; printf("<li οnclick=\"fill('%s%c')\">%s%c</li>", str, c, str, c); } int j=0; for (j=0; j<ALPHA_COUNT; j++) { if (root->ch[cur][j]) { char c = i+'\0'; char temp[128]; strcpy(temp, str); strcatch(temp, c); suggest_helper(root, temp, root->ch[cur][j], j, count); } } } void suggest(trie *root, char *str) { int i, cur = 0, n = strlen(str), count=0; for (i=0; i<n; i++) { int c = str[i] - '\0'; if (root->ch[cur][c]) { cur = root->ch[cur][c]; } else { printf("no suggestion found\n"); return; } } for (i=0; i<ALPHA_COUNT; i++) { if (root->ch[cur][i]) { suggest_helper(root, str, root->ch[cur][i], i, &count); } } } int http_get(char *key, char *query, char *result) { char *p = result; query = strstr(query, key); int write = 0; while (*query) { if (*query=='=') { query++; write = 1; continue; } if (write) { if (*query=='&') { *p = '\0'; return 1; } *p = *query; p++;query++; } else { query++; } } *p = '\0'; return 1; } int main() { trie *root = create(); char ch; FILE *fp; char line[255]; size_t len = 0; ssize_t read; char keyword[64]; if ((fp = fopen("phpfunc.txt", "r")) == NULL) { printf("open error\n"); exit(1); } while (fgets(line, 255, fp) != NULL) { char *end = strchr(line,'\n'); *end = '\0'; insert(root, line, strlen(line)); } while (FCGI_Accept() >= 0) { printf("Content-Type:text/html; charset=utf-8\n\n"); char *query = getenv("QUERY_STRING"); http_get("q", query, keyword); suggest(root, keyword); } return 0; }
然后编译gcc trie.c -o trie.cgi -I/etc/fcgi/include -L/etc/fcgi/lib/ -lfcgi
修改fcgi.conf
fastcgi.server = (
"trie.cgi" => ((
"host" => "127.0.0.1",
"port" => "9000",
"bin-path" => "/var/www/cgi-bin/trie.cgi",
))
)
在浏览器输入http://127.0.0.1:8080/trie.cgi?q=var
可以看到输出var_dump:var_export:variant_abs:variant_add:variant_and:variant_cast:variant_cat:variant_cmp:variant_date_from_timestamp:variant_date_to_timestamp:
下面是编写前端JS请求
index.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>Ajax Auto Suggest</title> <script type="text/javascript" src="http://ajax.aspnetcdn.com/ajax/jquery/jquery-1.8.0.js"></script> <script type="text/javascript"> function lookup(inputString) { $.get("http://192.168.2.165:8880/trie.cgi", {q: ""+inputString+""}, function(data){ if(data.length >0) { $('#suggestions').show(); $('#autoSuggestionsList').html(data); } }); } function fill(thisValue) { $('#inputString').val(thisValue); setTimeout("$('#suggestions').hide();", 200); } </script> <style type="text/css"> body { font-family: Helvetica; font-size: 11px; } h3 { margin: 0px; padding: 0px; } .suggestionsBox { position: relative; left: 30px; margin: 10px 0px 0px 0px; width: 200px; -moz-border-radius: 7px; -webkit-border-radius: 7px; border: 2px solid #000; } .suggestionList { margin: 0px; padding: 0px; } .suggestionList li { margin: 0px 0px 3px 0px; padding: 3px; cursor: pointer; } .suggestionList li:hover { background-color: #659CD8; } </style> </head> <body> <div> <form> <div> Type php functions: <br /> <input type="text" size="30" value="" id="inputString" onkeyup="lookup(this.value);" onblur="fill();" /> </div> <div class="suggestionsBox" id="suggestions" style="display: none;"> <img src="upArrow.png" style="position: relative; top: -12px; left: 30px;" alt="upArrow" /> <div class="suggestionList" id="autoSuggestionsList"> </div> </div> </form> </div> </body> </html>
因为服务器需要解析html文件所以在fcgi.conf中添加
mimetype.assign = (
".html" => "text/html",
)
启动lighttpd sudo /usr/local/webserver/lighttpd/sbin/lighttpd -D -f /usr/local/webserver/lighttpd/conf/fcgi.conf
在浏览器输入http://127.0.0.1:8080/index.html 就可以访问了。
fastcgi,swoole都一定程度弥补了php这种对于开发者类似CGI模式(如果不写PHP扩展,实际就是CGI模式~)对于开发者在开发网站时候的诸多不足。下一篇会介绍thrift并且用thrift编写一个主键生成服务器。