瞎折腾 FastCGI 和 spawn-fcgi 的一天

文章目录

……可以说是非常惨了

原始版本

起因是之前的一份 C++ 大作业是用 Web 方式实现的,然后用编译后的 CGI 作为后台进行处理数据、读写文件之类的工作,由于使用它需要有能运行 CGI 程序的进程,当时那个实际上是非常简单的 CGI……因为 POST 请求的数据是从 stdin 读入的(逃

那么这种程序就可以用 Apache 提供的可以运行 CGI 的模块去运行了,只需要做好一些简单的配置

首先,用滋瓷 C++11 标准的编译器编译成 CGI 程序,Apache用的是后缀名的方式识别 CGI 文件的,所以可执行文件的文件名应该以 .cgi 结尾:

$ g++ -std=c++11 -o api.cgi api.cpp

然后如果 Apache 没有配置执行 CGI 文件的话,需要改一下它的配置文件 httpd.conf,在部署这个项目的文件目录对应的项里(比如 <Directory "/var/www/html">)加上允许执行 CGI 的配置:

Options +ExecCGI  
AddHandler cgi-script .cgi  
但是其实在用这种方式配置上服务器的时候还是碰到了不少问题,比如说我用的系统是 CentOS 7,比如编译就成了第一个问题……官方的库里并没有支持 C++11 标准的 gcc 版本,不过还好已经有人给出了[解决方案](https://serverfault.com/questions/720558/how-to-install-gcc-5-2-on-centos-7-1),就是自己新建一个 Fedora 仓库,然后从这个仓库安装 gcc 5.1.1:
$ cat << EOF > /etc/yum.repos.d/Fedora-Core23.repo
[warning:fedora]
name=fedora  
mirrorlist=http://mirrors.fedoraproject.org/mirrorlist?repo=fedora-23&arch=$basearch  
enabled=1  
gpgcheck=0  
EOF

$ yum install gcc --enablerepo=warning:fedora
这个时候可以编译了,当然要带上 `-std=c++11` 选项,然后……发现报了一堆错,一开始以为大概是不可能成功安装上……药丸了药丸了,仔细看了一下报错信息好像是说 `index` 变量有点冲突,然后替换成了 `data_index`,再编译……OK 成功了 以及果然这 g++ 的报错信息是坠反人类的?

然后改好 httpd.conf (印象中好像也有点曲折,似乎是执行 CGI 的那个模块也不是本来就提供了的样子)之后访问了下,大概没什么问题了,那么就多做点测试……咦数据没写进文件蛙,怎么萎事

然后就不停用 chmod 改权限,甚至改到文件夹都 777 了还是没用,过了好久才发现不能有执行权限,然后

$ chmod 666 data.json

这样就可以成功对文件进行写操作了= =看来并不是说文件权限越高就真的能进行越多操作的,这个坑也踩了蛮久

然后到这里整个系统已经可以正常运作了,因为数据是写在文件里的,为了防止一些可能的意外,可以做个简单的定时备份:

$ mkdir backups
$ cd backups
$ echo "cp /deploy-directory/assets/API/data.json /deploy-directory/assets/API/backups/\`date +%m%d-%H.%M\`" > bak.sh

注意那两个反引号要转义一下,然后备份的文件名就是反引号内占位符所示的日期格式了,比如 1011-12.00

接下来把 bak.sh 文件加上执行权限,并编辑 CRON 加上定时任务:

$ chmod +x bak.sh
$ crontab -e

进入编辑页面后加上

0 */12 * * * sh /deploy-directory/assets/API/backups/bak.sh  

然后保存并返回,之后就会每 12 个小时备份一次数据,更准确地说应该是每个能整除 12 的小时,也就是零点和中午十二点

要注意的一点是不管是 bak.sh 文件里的命令还是备份命令都要写全路径,也就是要从根目录 / 写起,因为执行的时候并不是在文件夹内启动的,如果用相对路径的话就会找不到文件

备份没有正常进行的话可以查看一下 CRON 的日志,CentOS 下的文件是 /var/log/cron,不过因为我用的腾讯云的服务器,它们自己有一些每分钟一次的定时操作导致日志文件每天都很大,类似这种的情况应该要确定一下备份的时间然后只提取那一部分的日志:

$ grep "Oct  6 12:00" /var/log/cronNN

从 Apache 换到 spawn-fcgi

毕竟服务器用的 Web 服务管理是 Nginx, 再装个 Apache 只为了运行 cgi 实在是有点不值了……而且配置也算不上好,自从配置了 Apache 之后因为要一直运行着,经常就出现一些内存不够导致的问题,这是坠痛苦的

那么我就得想办法换个轻量级的能运行 CGI 的程序了,然后选中了 spawn-fcgi

$ wget http://download.lighttpd.net/spawn-fcgi/releases-1.6.x/spawn-fcgi-1.6.4.tar.gz
$ tar zxvf spawn-fcgi-1.6.4.tar.gz
$ cd spawn-fcgi-1.6.4/

然后按照官方给的安装步骤做:

$ ./configure
# If ./configure is missing, run ./autogen.sh.
$ make
$ make install

安装好之后绑定 CGI 试试看

$ spawn-fcgi -a 127.0.0.1 -p 8081 -f /xxxxxx/api.cgi

emmmm

spawn-fcgi: child exited with: 0

似乎并没有成功运行,检查一下8081端口是不是正在监听: netstat -nap | grep 8081 果然并没有

另外还要提一下有两个可能比较容易碰到的报错:

spawn-fcgi: child exited with: 126

这种情况是因为 -f 参数后面跟的是目录,而应该提供的是直接的一个 CGI 程序文件

spawn-fcgi: child exited with: 127

这种情况就是提供的参数是一个文件名,但是文件有问题,比如文件不存在或者没有执行权限等

FastCGI

Stack Overflow链接

char * method = getenv("REQUEST_METHOD");  
if (!strcmp(method, "POST")) {  
    int ilen = atoi(getenv("CONTENT_LENGTH"));
    char *bufp = malloc(ilen);
    fread(bufp, ilen, 1, stdin);
    printf("The POST data is<P>%s\n", bufp);
    free(bufp);
}

In C++, you need to cast the return of malloc()

所以把中间的那行改成 char *bufp = (char*)malloc(ilen); 就可以了

处理好不带数据的请求

还没写完QAQ 先放上来吧