FCGIWRAP: Simple FastCGI wrapper for CGI scripts。
首先说一下这个东西的作用。它为那些不支持直接运行 CGI脚本 的 Web 服务器提供一种运行 CGI脚本 的方式。
CGI 诞生已经非常久远了,由于它每次在处理一个请求(连接)时都要重新启动脚本(可执行文件),重新传递所有的环境变量(其中非常多是完全一样的),导致性能非常低下。虽然性能较低,但功不可没,后来出现了性能更高的 FastCGI。
FastCGI 性能更高的原因在于,它是常驻内存的,一个 FastCGI 进程可以处理任意多个连接。后来又出现了 Spawn-FCGI,其使得 FastCGI 的进程数可以根据服务器的压力状况动态地创建 FastCGI 进程,这样,可伸缩性就更强了。
现在的 FastCGI 实现中,多数并没有实现标准的 FastCGI,导致性能依然不是特别高。同样没有完全避免重复的过程,比如:不变环境变量(服务器版本,用户家目录)的传递。但它不属于本文的范畴,我也就不多说了。
NGINX 就是一个只支持 FastCGI,不支持 CGI 的 HTTP(Web)服务器之一。也是我用得最多最熟悉的 Web 服务器。虽然 Apache 支持直接跑 CGI,但从来没用过它的我对它并不感冒,这里也就不再讨论了。
下面我将以 Ubuntu 为例简单介绍下。
fcgiwrap 的使用非常的简单。看源代码应该能看出来,不到 1000 行的程序,能有多复杂?
首先是安装(我就不编译了):
root@ubuntu:~# apt-get install fcgiwrap
,它把 spawn-fcgi 也装上了,不过也无关紧要,本文不会用到。
这玩意儿简单到不需要配置文件,只需要提供少数参数即可。
root@ubuntu:~# fcgiwrap -h
Usage: fcgiwrap [OPTION]
Invokes CGI scripts as FCGI.
fcgiwrap version 1.1.0
Options are:
-f Send CGI's stderr over FastCGI
把 CGI 的 标准出错 也重定向到 FastCGI,多用于开发环境
-c <number> Number of processes to prefork
需要预先启动的子进程数
-s <socket_url> Socket to bind to (say -s help for help)
与 Web服务器 进行 FastCGI 通信用的 套接字(格式见下面)
-h Show this help message and exit
-p <path> Restrict execution to this script. (repeated options will be merged)
Report bugs to Grzegorz Nosek <root@localdomain.pl>.
fcgiwrap home page: <http://nginx.localdomain.pl/wiki/FcgiWrap>
root@ubuntu:~# fcgiwrap -s help
Valid socket URLs are:
unix:/path/to/socket for Unix sockets
tcp:dot.ted.qu.ad:port for IPv4 sockets
tcp6:[ipv6_addr]:port for IPv6 sockets
root@ubuntu:~#
我直接使用的 unix域 形式:
root@ubuntu:~# # 后台跑起来 root@ubuntu:~# fcgiwrap -f -s unix:/var/run/fcgiwrap.socket & [1] 1577 root@ubuntu:~# # 确实已经跑起来了 root@ubuntu:~# ps aux | grep '[f]cgiwrap' root 1577 0.0 0.0 1600 512 pts/0 S 00:29 0:00 fcgiwrap -f -s unix:/var/run/fcgiwrap.socket root@ubuntu:~# # 监听套接字存在 root@ubuntu:~# ls -l /var/run/fcgiwrap.socket srwxr-xr-x 1 root root 0 Jun 15 00:29 /var/run/fcgiwrap.socket root@ubuntu:~# # 因为我是用 root 执行的,所以得有这一步 root@ubuntu:~# chmod a+rw /var/run/fcgiwrap.socket root@ubuntu:~# ls -l /var/run/fcgiwrap.socket srwxrwxrwx 1 root root 0 Jun 15 00:29 /var/run/fcgiwrap.socket
OK,现在 Web服务器 和 FastCGI(Wrap) 已经跑起来了,接下来我写个简单的 CGI 脚本,用于打印出当前请求的资源和查询字符串。
#!/bin/bash echo -ne 'Status: 200\r\n' echo -ne 'Content-Type: text/plain\r\n' echo -ne '\r\n' echo 'PATH_INFO: ' $PATH_INFO echo 'QUERY_STRING: ' $QUERY_STRING exit 0
,这是很简单的一个 Shell 脚本,直接打印环境变量,我直接放在了家目录根下,文件名是 `echo`(/root/echo),注意修改为可执行。
下面是 nginx 的配置:
location / { fastcgi_param SCRIPT_FILENAME "/root/echo"; fastcgi_param PATH_INFO $uri; fastcgi_param QUERY_STRING $args; fastcgi_param HTTP_HOST $server_name; fastcgi_pass unix:/var/run/fcgiwrap.socket; include fastcgi_params; # 必须放在最后 }
,重启 nginx 后,用 curl 请求查看结果:
root@ubuntu:~# curl http://localhost/path/to/file?query=12345
PATH_INFO: /path/to/file
QUERY_STRING: query=12345
root@ubuntu:~#
可以看到的是,路径与查询信息都已经正确打印出来了,一切运行正常。