C++web实践(CGI编程)

什么是CGI?CGI(The Common Gateway Interface):通用网关接口,定义web服务器和客户脚本进行信息交互的一系列标准。 为了了解CGI的概念,让我们来看看当我们单击一个超链接来浏览一个特定的web页或URL的时候,背后会发生什么事?

在进行网页浏览时,通常就是通过一个URL请求一个网页,然后服务器返回这个网页文件给浏览器。浏览器在本地解析该文件渲染成我们看到的网页。然而通常我们看到的网页不是静态网页,也就是说在服务端是没有这个网页文件,它是在网页请求的时候动态生成的,比如PHP/JSP网页。依据你请求的参数不同,所返回的内容不同。 同理,如果是请求一个CGI程序的时候(比如在浏览器直接输入CGI程序的URL,或者提交表单的时候发送给CGI程序),CGI程序负责解析从前端传递过来的参数,理解它的意图然后返回数据,比如返回HTML、XML或JSON等。 CGI(The Common Gateway Interface)是一个标准化的协议,能够使应用程序(通常称为CGI程序或CGI脚本)同web服务器和客户端进行交互。CGI程序能够用Python, PERL, Shell, C or C++等语言来实现。 在PHP和Java大行其道的今天,很多人看来用C++编写CGI是几乎淘汰的技术了(其实这到不然,只是比较小众罢了)。所以如果你对C/C++感兴趣或者对历史感兴趣都可以继续阅读下去。 下图简单的展示了CGI程序架构 在你着手写CGI程序之前,确保你的web服务器支持CGI程序并且配置成处理CGI程序。所有的能够被HTTP服务器执行的CGI程序都被存放在预先配置好的目录下面,这个目录叫做CGI目录,并且按照约定命名为 /var/www/cgi-bin,并且约定CGI文件的后缀名为.cgi ,尽管它们是c++可执行文件。 一般的,Apache 服务器在/var/www/cgi-bin目录下配置文件来运行CGI程序,如果你想要声明另外的目录来运行CGI脚本,你需要修改httpd.conf 文件中的部分内容:

<Directory “/var/www/cgi-bin”>
AllowOverride None
Options ExecCGI
Order allow,deny
Allow from all

<Directory “/var/www/cgi-bin”>
Options All

配置好之后。就可以用C/C++编程了! 第一步:我们编写一个这样的文件

#include<stdio.h>
int main(int args ,char * argv []) {

printf("Content-type:text/html\\n\\n");
printf("hello world ! 我是cgi ");
getchar();

return 0;
}

编译,生成一个这样的 hello.exe文件、生成之后,我们将hell.exe的属性改为 hello.cgi,然后将其放置到,自己安装的Apache server文件中的cgi-bin文件下,在浏览器中,再输入http://localhost/cgi-bin/hello.cgi  就可以看到这样的画面   那我们该如何用c/c++写一个cgi来做后台,在背后来操作这个数据呢! 首先,我们需要写一个html。

表单提交

输入命令:

运行效果如图: 最后就是重点了! 像上面写的cgi一样! 写一个下面这样的代码:

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
//#include
#include<windows.h>

//以调用System为举例
void func(char ps []) {
// ps 为cmd命令
char *pl = strchr(ps,’=’); //pl指向当前的位置
if(pl!=NULL) ps = ps + (pl-ps+1);
printf(“命令cmd = %s\n”, ps);
char cmd[256] = {‘\0’};
char filename[] = “Tcmd.txt”; //暂定放置于当前目录。
sprintf(cmd,”%s > %s “,ps,filename); //将ps的内容写入cmd中
//生成了一条指令
//无论是否执行成功,都会生成一个Tcmd.txt文件
FILE *fp = NULL;
int tag=system(cmd);
if (tag == 1) {
printf(“命令格式错误!,请重新输入: “);
goto loop;
}
if ((fp = fopen(filename, “r”)) == NULL) {
printf(“没有发现文件!”);
goto loop ;
}

 while (!feof(fp)) {
     char str=fgetc(fp);
      if (str == '\\n') printf("<br><br>\\n\\n");
      else if (str == ' ')printf("&nbsp;");
      else
          printf("%c",str);
 }

loop:
if (fp != NULL){
fclose(fp);
//并删除备份的文件
system(“del Tcmd.txt”);
}
return ;
}

int main(int args ,char * argv []) {

printf("Content-type:text/html\\n\\n");
//打印环境变量
printf("&nbsp;&nbsp;&nbsp;%s<br><br>", getenv("QUERY\_STRING"));
char szPost\[256\] = {'\\0'};
gets(szPost);  //获取输入    
if ( strlen(szPost) < 1 )
    strcpy( szPost , "ipconfig" );
func(szPost);
getchar();

return 0;
}

编译之后,形成cmd.exe,将cmd.exe属性改为cmd.cgi文件,放置到cgi-bin目录中,当然,如果有服务器,之间放到服务器中就可以看! 然后打开浏览器就能访问了,在输入框里输入cmd命令再点击ok就能预览效果了。 CGI是一种标准,并不限定语言。所以Java、PHP、Python都可以通过这种方式来生成动态网页。但是实际上这些动态语言却很少这样用。原来是CGI有一大硬伤。那就是每次CGI请求,那么Apache都有启动一个进程去执行这个CGI程序,即颇具Unix特色的fork-and-execute。当用户请求量大的时候,这个fork-and-execute的操作会严重拖慢Server的进程。而Java的Servlet技术则是一种常驻内存的技术,不会频繁的发生进程上下文的创建和销毁操作。 时势造英雄,FastCGI技术应运而生。简单来说,其本质就是一个常驻内存的进程池技术,由调度器负责将传递过来的CGI请求发送给处理CGI的handler进程来处理。在一个请求处理完成之后,该处理进程不销毁,继续等待下一个请求的到来。FCGI技术一出,CGI又一定程度上焕发了第二春。PHP-FPM本身是使PHP支持FCGI技术的一个Patch,现在已经被纳入PHP标准。当然,支持C++的FCGI技术也出现了,Apache有FCGI的模块可以安装,比如mod_fcgid。 前面我们知道,CGI可以直接返回一个html网页。CGI程序本身也可以进行各种计算、逻辑处理任务。随着各类web前后端技术的发展,以及大数据、高并发的Server使用场景越来越多。现代的CGI的用法,在发生变化。 现在,越来越多的任务从后端转移到前端,前端页面利用丰富的Js技术来进行更多的处理。 JS可以使用Ajax技术来向后台CGI发起数据请求。Ajax完成的是不需要刷新整个页面就可以加载后端数据(比如从数据库中取出)。 CGI一般不再用于直接返回html页面,同时将复杂的计算、IO任务下沉到后端(后端可以进一步进行路由转发,实现负载均衡)。使CGI作为前后端之间的中间层。彼时CGI的职能是完成基本的数据交换:解析前端数据请求,再转发给对应后端;然后从后端取回数据,给前端返回XML或JSON。 前端JS利用XML/JSON中的数据来进行填充,绘制出丰富的页面。


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!