1.cgi文件的代码
#include "fcgi_stdio.h" #include <stdlib.h> #include <stdio.h> int main() { /* Initialization Code */ int count = 0; /* Start of response loop */ while (FCGI_Accept() >= 0) { //* body of response loop /*/ //FCGI_printf("Content-type: text/html/r/n" // "/r/n" // "" // "FastCGI Hello/! (C, fcgi_stdio library)" // "Request number %d running on host %s " // "Process ID: %d/n",++count,getenv("SERVER_NAME"), getpid()); FCGI_printf("Content-type: text/html\r\n\r\n"); FCGI_printf("<title>FastCGI Hello HI! (C, fcgi_stdio library)</title>\n"); FCGI_printf("Request number %d running on host %s Process ID: %d\n",++count,getenv("SERVER_NAME"), getpid()); } /* End of response loop */ return 0; }
过程中可能遇到一些问题,提示502的错误,原因在代码的cgi问题。
使用fastcgi c api时注意的问题
最近用fastcgi的c语言api写服务,发现一个问题。我用nginx来接收请求,并通过fastcgi_pass传递到c程序。在用curl测试请求的时候,发现c程序是有被调用的,但是nginx返回的响应一直是502 "upstream closed prematurely FastCGI stdout while reading response header from upstream"。在网上找了很久,也有同样的问题,但是一般都是说原因是printf的时候没有按照http协议,比如说一定要printf("Content-type: text/html \r\n\r\n")。我按照这个格式写了,但还是出错。最后发现是由于include了c和c++的一些头文件,比如,下面的代码就有可能出现这样的问题(也有可能不出现问题):
#include "fcgi_stdio.h" #include <iostream> #include <string> #include <map> #include <stdlib.h> #include <stdio.h> int main() { while(FCGI_Accept() >= 0) { ////////////////////////////////////////////////////////////////////////// //get content type and length ////////////////////////////////////////////////////////////////////////// printf("Content-type: text/*\r\n\r\n"); printf("<title>FastCGI Hello! (C, fcgi_stdio library)</title>\n"); } }
在官方的api使用例子里面,只有include “fcgi_stdio.h”和“stdlib.h”这两个头文件。于是我看了一下fcgi_stdio.h这个文件,发现它定义了一个宏,也叫printf,而事实上是调用了FCGI_printf这个函数。 而include其他的头文件可能会导致链接的时候链接到原来的printf实现,所以最保险的做法是:
#include "fcgi_stdio.h" #include <iostream> #include <string> #include <map> #include <stdlib.h> #include <stdio.h> int main() { while(FCGI_Accept() >= 0) { ////////////////////////////////////////////////////////////////////////// //get content type and length ////////////////////////////////////////////////////////////////////////// FCGI_printf("Content-type: text/*\r\n\r\n"); FCGI_printf("<title>FastCGI Hello! (C, fcgi_stdio library)</title>\n"); } }
2.nginx的配置文件
#user nobody; #daemon off; #master_process off; worker_processes 1; error_log logs/80_error.log; error_log logs/80_notice.log notice; error_log logs/80_info.log info; error_log logs/80_debug.log debug; pid logs/80.pid; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; error_log logs/80_http_debug.log debug; access_log logs/80_http_access.log main; sendfile on; #tcp_nopush on; #keepalive_timeout 0; keepalive_timeout 65; #gzip on;
//部署负载均衡 #upstream resinserver{ # server 127.0.0.1:8081 weight=1; # server 127.0.0.1:8082 weight=1; # server 127.0.0.1:8083 weight=1; # keepalive 1024; #} server { listen 8080; server_name 192.168.104.101 127.0.0.1 localhost; #charset koi8-r; #access_log logs/host.access.log main; #location / { # root html; # index index.html index.htm; #proxy_pass http://resinserver/; #proxy_set_header Host $host; #proxy_set_header X-Real-IP $remote_addr; #proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; #} //部署cgi文件 #location ~/.cgi$ { # fastcgi_pass 127.0.0.1:9002; # fastcgi_index index.cgi; # fastcgi_param SCRIPT_FILENAME cgibin$fastcgi_script_name; # include fastcgi_params; #} #error_page 404 /404.html; # redirect server error pages to the static page /50x.html # #error_page 500 502 503 504 /50x.html; #location = /50x.html { # root html; #} # proxy the PHP scripts to Apache listening on 127.0.0.1:80 # #location ~ \.php$ { # proxy_pass http://127.0.0.1; #} # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 #
//这是我自己添加的 location ~\.cgi$ { root /usr/local/nginx/cgibin; fastcgi_pass 127.0.0.1:9002; fastcgi_index index.cgi; fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name; include fastcgi_params; } # deny access to .htaccess files, if Apache's document root # concurs with nginx's one # #location ~ /\.ht { # deny all; #} } # another virtual host using mix of IP-, name-, and port-based configuration # #server { # listen 8000; # listen somename:8080; # server_name somename alias another.alias; # location / { # root html; # index index.html index.htm; # } #} # HTTPS server # #server { # listen 443 ssl; # server_name localhost; # ssl_certificate cert.pem; # ssl_certificate_key cert.key; # ssl_session_cache shared:SSL:1m; # ssl_session_timeout 5m; # ssl_ciphers HIGH:!aNULL:!MD5; # ssl_prefer_server_ciphers on; # location / { # root html; # index index.html index.htm; # } #} }
3.编译1.cgi
gcc -o 1.cgi 1.c -lfcgi
4.运行1.cgi文件
注意这是一行命令哦。注意可能要sudo.
-p是指定fastcgi控制器绑定的TCP端口listen的.
如果你想调试单个fastcgi程序,可以把-f换成-n.
-F指定spawn-fcgi将fork多少个child进程。之后nginx对于此cgi的请求就可以并发了。显然这里的直接并发量是1000.
其他参数可以help看看:(看起来-C对不要php的我来说没啥用.本文是初次使用记录性教程,这里就不纠结这些参数了)
Lenovo:/usr/local/nginx$ sbin/spawn-fcgi --help
/usr/local/nginx/sbin/spawn-fcgi -a 127.0.0.1 -p 9002 -C 25 -f /usr/local/nginx/cgibin/1.cgi
监听的端口是9002,对应nginx的配置文件的9002
关闭spawn-fcgi打开的fastcgi程序:
$ netstat -anp | grep 9000 #查看占用9000端口的程序ID
$ kill -9 PID #或killall 进程名
5.运行nginx
./sbin/nginx -c nginx.conf
6.在浏览器查看
http://192.168.104.101:8080/1.cgi
这是网上的一些测试,待有时间再做验证,先保存起来。。。
3.webbench压力测试工具
下载:http://home.tiscali.cz:8080/~cz210552/distfiles/webbench-1.5.tar.gz
安装:
tar zxvf webbench-1.5.tar.gz cd webbench-1.5
make && make install
使用:
webbench -c 500 -t 30 http://127.0.0.1/test.jpg
500是并发连接数,30是时间单位是秒
用ab测试的结果,在我的虚拟机上,看起来性能很不错
(Apache Bench是Apache自带的工具包)
ab -n 10000 -c 100 http://127.0.0.1/1.cgi
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking 127.0.0.1 (be patient)
Completed 1000 requests
Completed 2000 requests
Completed 3000 requests
Completed 4000 requests
Completed 5000 requests
Completed 6000 requests
Completed 7000 requests
Completed 8000 requests
Completed 9000 requests
Completed 10000 requests
Finished 10000 requests
Server Software: nginx/0.7.38
Server Hostname: 127.0.0.1
Server Port: 80
Document Path: /1.cgi
Document Length: 143 bytes
Concurrency Level: 100
Time taken for tests: 3.982 seconds
Complete requests: 10000
Failed requests: 8399
(Connect: 0, Receive: 0, Length: 8399, Exceptions: 0)
Write errors: 0
Total transferred: 2658399 bytes
HTML transferred: 1438399 bytes
Requests per second: 2511.06 [#/sec] (mean)
Time per request: 39.824 [ms] (mean)
Time per request: 0.398 [ms] (mean, across all concurrent requests)
Transfer rate: 651.89 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 1 4.6 0 51
Processing: 22 39 6.8 36 93
Waiting: 4 39 6.8 36 93
Total: 24 39 8.2 36 97
Percentage of the requests served within a certain time (ms)
50% 36
66% 39
75% 41
80% 42
90% 48
95% 54
98% 70
99% 84
100% 97 (longest request)
4.Nginx模块
模块列表
http://wiki.codemongers.com/NginxModules
FastCGI模块源码:nginx/src/http/modules/ngx_http_fastcgi_module.c