最近事情比较多,也没有怎么更新文章。正好昨天突然想到要给这个小站的底部放一个访问计数器,就是“您是本站第XXX位访客”这样的。用PHP实现当然很简单,但是今天我不用PHP,而用C语言来编写这个网站计数器的后端。通过这个很简单的例子,我们可以体会到CGI编程的作用和相关规范。
首先来叙述一下CGI编程的规范。PHP, ASP等程序都可以看成是CGI程序,而CGI程序并不一定要以这些脚本语言编写。用其他任何计算机语言,比如C, C++, Delphi等都是可以的。客户端提交数据给服务端CGI程序进行处理,CGI程序处理后返回给客户端浏览器,这就是完整的CGI工作流程。客户端GET, POST等方式提交的表单等数据,是作为参数一并提交给CGI程序的,因此,以C语言为例,我们以
1 | int main(int argc, char * argv[]) |
的方式编写CGI程序就可以接收到提交的参数并进行处理。CGI程序给浏览器的输出是服务器程序将标准输出(stdout)重定向后实现的,因此我们只要向stdout按照一定规范输出数据,该数据将可以立即显示在客户端浏览器上。
下面我们来进行这个C语言网站计数器的编写。整个计数器分为前端和后端两个部分,后端为C语言编写的CGI程序,前端可以使用Ajax或者PHP的Curl等功能进行CGI程序的调用。服务器的环境是CentOS 5 32bit/Apache, 其他服务器比如Nginx应当类似。CGI程序需放置在cgi-bin目录中,我这里是/var/www/cgi-bin/, 若找不到的话可以在终端(或SSH)中执行
1 | find / -name cgi-bin |
命令来查找。另外,编译C源程序需要安装gcc, CentOS下可以执行
1 | yum install gcc |
来安装,Debian下执行
1 | apt-get install gcc |
安装。
计数器的工作流程是这样的:前端页面被访问,调用CGI程序,CGI程序读取之前的访问量并将其加一后返回给前端页面。为了方便、简洁与高效,我们使用磁盘文件而不是MySQL来存储这样一个访问量数据。另外,我们可以实现分别统计总访问量和当天访问量的功能,只需在磁盘中分别储存这两个数据,每天24:00时让系统自动执行一个初始化的脚本将当天访问量的数据清零即可。网站计数器的CGI部分如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | #include int main(void) { FILE * fp; long counter[2]; printf("Content-type: text/html\n\n"); //注 if ((fp=fopen("/var/counter.dat","rb+")) == NULL){ puts("Failed in opening file."); exit(1); } fread(counter,sizeof(*counter),2,fp); printf("You are No.%ld visitor today, and No.%ld visitor in all.",++*counter,*(counter+1)+*counter+1); rewind(fp); fwrite(counter,sizeof(*counter),1,fp); fclose(fp); return 0; } |
需要注意的是我标注的那一行,这是CGI编程规范的一部分,就是CGI程序给浏览器的输出的第一行必须是标题,比如这里的Content-type: text/html,且标题后必须要有一个单独的空行。只有输出了这样的标题后CGI程序才能继续向浏览器输出,否则访问时会产生500错误。
上面这个程序读入的数据的位置是/var/counter.dat, 因此在运行之前需要保证这个文件已经建立,并且权限足够(需要将其用户组属设为apache服务器的用户)。程序中sizeof(long)一般为4,不过可能由于编译环境不同而有差异。另外,为了速度,程序读文件采用的是二进制流,因此/var/counter.dat可能需要用程序来建立,或者使用DD命令亦可,长度为8个字节。
将上面这个程序编译连接后命名为counter.cgi, 然后复制到cgi-bin目录下,这时我们在浏览器中访问http://your_ip/cgi-bin/counter.cgi应该能看到一句话的正确的输出,若访问遇到500错误,请自行检查Apache错误日志进行错误排查。
下面我们再编写一个程序用于每天24点自动将当天访问量清零。如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | #include #include int main(void) { FILE * fp; long counter[2]; if ((fp=fopen("/var/counter.dat","rb+")) == NULL){ puts("Failed in opening file."); exit(1); } fread(counter,sizeof(*counter),2,fp); *(counter+1)=*counter+*(counter+1); *counter=0; rewind(fp); fwrite(counter,sizeof(*counter),2,fp); fclose(fp); printf("\nInitialized.\n"); return 0; } |
编译后设置计划任务即可。这样,后端我们就编写完毕了。需要指出的是,我上面第一个程序已经将返回到浏览器的输出形式写好了,如果不喜欢这样的形式则可以自行更改,也可以输出一串json格式的数据由前端Javascript或者PHP进行解析,这都是可以的。
前端部分可以用Javascript的XMLHttpRequest对象,即类似Ajax的方式实现,也可以用PHP的file_get_contents()等函数获取CGI程序的输出,这里以Javascript为例简要说明CGI程序的调用。假设已新建GetCounter为XMLHttpRequest的实例,则:
1 2 3 4 5 6 7 8 9 10 11 12 13 | function RequestNumber() { var CGI_url="http://your_ip/cgi-bin/counter.cgi"; GetCounter.onreadystatechange=showNumber; GetCounter.open("GET",CGI_url,true); GetCounter.send(null); } function showNumber() { if (GetCounter.readyState == 4) { if (GetCounter.status == 200) { counter.innerHTML = GetCounter.responseText; } } } |
我们在页面底部新建一个<div id=”counter”></div>的标签,则使用Javascript调用RequestNumber()函数即可在网页底部看到计数器的输出了。至此,这个用C语言编写的另类计数器全部编写完毕。
可以看出,很多类似的工作,比如数据库查询、用户登录处理等内容都可以使用其他语言编写的CGI程序来完成,其优势在于安全性高、无数据库连接信息泄露危险、运算及执行速度快、字符与文件处理能力强等。以后我将写一些CGI编程其他方面,如环境变量、标题设置,以及文件上传、表单提交等功能的实现等内容。转载请注明转自香菇肥牛的博客http://qing.su
不错,学习了。。。
学到了,CGI 脚本是任何运行在web服务器上的程序. CGI意思是Common Gateway Interface,上面的c,c++,c#等等都是放在/var/www/cgi-bin/里么
可以放在这个里面,也可以为服务器上的每个网站单独设置文件夹
哇!!
1看到了这个代码高亮插件也不错
2涨姿势了原来C语言也可以用于网页
3了解到了cgi-bin的意思,以前我只知道网页不存在有时会打开cgi-bin/default.cgi
4为什么不在底部放个演示呢
这个破插件没法缩进。。。。。= =
嗯嗯,好建议~谢啦~