CGI介绍

1、什么是CGI

2、CGI和Webserver的区别

2、CGI的标准输入和标准输出

3、CGI的环境变量

4、CGI程序数据处理的一般工作流程

5、CGI中From表单数据的分析和解码 


1、什么是CGI

    CGI即通用网关接口(Common Gateway Interface),是一个Web服务器主机提供信息服务的标准接口。通过CGI接口,Web服务器就能够获取客户端提交的信息,转交给服务器端的CGI程序进行处理,最后返回结果给客户端。CGI通信系统的组成是两部分:一部分是html页面,就是在用户端浏览器上显示的页面。另一部分则是运行在服务器上的Cgi程序。CGI程序可以是Python脚本,PERL脚本,SHELL脚本,C或者C++程序等,CGI的架构图如下:

                                            

2、CGI和Webserver的区别

     CGI是一种标准,Webserver则是一种应用。从浏览器的角度来看,浏览器只负责发送请求,接收来自Webserver的返回结果并渲染之。对于Webserver来讲,它需要做的仅仅是接收请求,寻找浏览器请求的文件并且发送回去。但是我们不光要浏览静态网页,网站中也存在大量动态网页,比如我们还要登陆网站、上传文件等,这些涉及和用户交互的功能,只用静态网页时无法实现的,因此我们需要一种动态语言来处理客户端的交互请求,由于有很多动态语言和很多种Web服务器,他们彼此之间互不兼容,给程序员造成了很大的麻烦。那么,CGI应运而生。CGI的定义是统一网关接口。从此Webserver收到后台动态交互请求就直接发CGI,CGI发给动态语言,动态语言把结果发回给CGI,CGI再发回给Webserver。

    最初的、最简单的CGI,是使用C来写的,很简单。到了后来,由于C的开发效率太低,于是PHP、ASP、Java、Perl、Python这些高级语言就纷纷加入。

  • ASP由于是微软一家单独支撑,不开源,并且需要买微软的服务器软件,用的人比较少。
  • 用Java语言来写CGI,就是JSP技术。
  • PHP名为超文本预处理语言,从这个名字可以看出,就是专门为动态网页而生的,它的好处是可以潜入HTML,而不是像C那样重新生成整个文本。这个现在已经不是优势了,JSP一样可以做到这点。PHP由于是动态加载,边解释边执行,所以效率没有java高,这个问题可以用预编译和使用C、C++模块来解决。

       这些语言里面,Java的发展是最迅速的,所以Java产生了一堆好东西,比如Tomcat,比如IBM的Websphere,WebSphere是真正的应用服务器,而Tomcat还算不上,因为他还不能真正支持很多J2EE的API,但是Tomcat作为servlet的容器,基本满足写CGI的需求,这样使得Tomcat被使用得非常广泛。Tomcat全部使用java完成,它是单进程结构,是使用CPU密集型的架构来设计的,这样Tomcat在处理大规模的Web请求时,根本没法处理。所以很多人说,使用apache处理静态网页,使用tomcat处理动态网页。除了Java使用Tomcat容器来进行支撑外,其他的CGI就很low了,都是脚本,一是需要边解释边执行,二是这些个脚本的CGI,都是使用其解释器+CGI部分合成一个CGI程序,比如apache接收到请求后,就启动一个CGI程序,生成动态内容后,CGI程序退出。这种方式显然是不行的,效率非常低,所以,fastCGI就出来了,fastCGI在CGI和web服务器中间再加了一层。

2、CGI的标准输入和标准输出

(1)标准输入

    CGI程序的标准输入是与Web服务器的标准输出对应的,看起来就像其他可执行程序一样通过标准输入(stdin)得到输入信息,实则这些数据是由浏览器传递给服务器后再由服务器定向到CGI的输入中的,如Form表单中的数据,这就是所谓的Web浏览器通过Web服务器与CGI后台可执行程序进行信息交互的方法。这也意味着在操作系统命令行状态可执行CGI程序,对CGI程序进行调试。对于CGI来说数据传输方法分为POST和GET方法。

(2)标准输出

    CGI程序通过标准输出(stdout)将输出信息传送给Web服务器,CGI的标准输出对应的是Web服务器的标准输入。传送给Web服务器的信息可以用各种格式,通常是以纯文本或者HTML文本的形式,这样我们就可以在命令行状态调试CGI程序,并且得到它们的输出。

    CGI程序产生的输出由两部分组成:MIME头信息和实际的信息。两部分之间以一个空行分开。请注意任何MIME头信息后必须有一个空行。如:

prinft (″Content type :text/plain%d%d″,10, 10); 

    此行通过标准输出将字符串[″Contenttype :text/plain%d%d″, 10, 10]传送给Web服务器。它是一个MIME头信息,它告诉Web服务器随后的输出是以纯ASCII文本的形式。请注意在这个头信息中有两个换行符,这是因为Web服务器需要在实际的文本信息开始之前先看见一个空行。一旦发送这个MIME头信息给Web服务器后,Web浏览器将认为随后的文本输出为HTML源代码,在HTML源代码中可以使用任何HTML结构,如超链、图像、Form,及对其他CGI程序的调用。也就是说,我们可以在CGI程序中动态产生HTML源代码。

3、CGI的环境变量

    操作系统提供了许多环境变量,它们定义了程序的执行环境,应用程序可以存取它们。Web服务器和CGI接口又另外设置了自己的一些环境变量,用来向CGI程序传递一些重要的参数。下面是CGI程序设计中用得比较频繁的一些环境变量:

  • SERVER-NAME:运行CGI序为机器名或IP地址。
  • SERVER-INTERFACE:WWW服务器的类型,如:CERN型或NCSA型。
  • SERVER-PROTOCOL:通信协议,应当是HTTP/1.0。
  • SERVER-PORT:TCP端口,一般说来web端口是80。
  • HTTP-ACCEPT:HTTP定义的浏览器能够接受的数据类型。
  • HTTP-REFERER: 发送表单的文件URL。(并非所有的浏览器都传送这一变量)
  • HTTP-USER-AGENT:发送表单的浏览器的有关信息。
  • GETWAY-INTERFACE:CGI程序的版本,在UNIX下为 CGI/1.1。
  • PATH-TRANSLATED: PATH-INFO中包含的实际路径名。
  • PATH-INFO:浏览器用GET方式发送数据时的附加路径。
  • SCRIPT-NAME: CGI程序的路径名。
  • REQUEST-METHOD:指的是当Web服务器传递数据给CGI程序时所采用的方法,分为GET和POST两种方法。GET方法仅通过环境变量 (如QUERY-STRING)传递数据给CGI程序,而POST方法通过环境变量和标准输入传递数据给CGI程序,因此POST方法可较方便地传递较多的数据给CGI程序。
  • QUERY-STRING:表单输入的数据,URL中间号后的内容。
  • REMOTE-HOST:发送程序的主机名,不能确定该值。
  • REMOTE-ADDR:发送程序的机器的IP地址。
  • REMOTE-USER:发送程序的人名。
  • CONTENT-TYPE:POST发送,一般为applioation/xwww-form-urlencoded。
  • CONTENT-LENGTH:传递给CGI程序的数据字符个数(字节)。Web服务器在调用使用POST方法的CGI程序时设置此环境变量,它的文本值表示Web 服务器传送给CGI程序的输入中的字符数目,因此我们使用函数atoi() 将此环境变量的值转换成整数,并赋给变量n。请注意Web服务器并不以文件结束符来终止它的输出,所以如果不检查譔环境变量,CGI程序就无法知道什么时候输入结束。

在C语言程序中,要访向环境变量,可使用getenv()库函数。例如: 

if (getenv (″CONTENT-LENGTH″)) 
   n=atoi(getenv (″CONTENT-LENGTH″)); 

  请注意程序中最好调用两次getenv():第一次检查该环境变量是否存在,第二次再使用该环境变量。这是因为函数getenv()在给定的环境变量名不存在时,返回一个NULL(空)指针,如果你不首先检查而直接引用它,当该环境变量不存在时会引起CGI程序崩溃。

4、CGI程序数据处理的一般工作流程

  • 通过检查环境变量REQUEST-METHOD确定客户端所使用的数据传递方法,POST还是GET方法。
  • 通过检查环境变量CONTENT-LENGTH,确定有多少输入;
  • 从相应环境变量中或标准输入中得到所有的用户数据;
  • 以相应的方法处理输入数据,如解码用户数据以提取所需信息、保存数据以更新配置文件等等;
  • 通过″Contenttype:″头信息,将输出信息的格式告诉Web服务器;
  • 通过使用printf()或者putchar()或者其他的文件写函数,将输出传送给Web服务器。 

5、CGI中Form表单数据的分析和解码 

    当用户提交一个HTMLForm时,Web浏览器首先对Form中的数据以名字/值对的形式进行编码,并发送给Web服务器,然后由Web服务器传递给CGI程序。

    URL编码规则:每对name/value由&符分开;每对来自表单的name/value由“=”符分开。如果用户没有输入值给这个name,那么这个name还是出现,只是无值。任何特殊的字符(就是那些不是简单的七位ASCII,如汉字)将以百分符%用十六进制编码,当然也包括象 =、&、% 这些特殊的字符。其实url编码就是一个字符ascii码的十六进制。不过稍微有些变动,需要在前面加上“%”。比如“\”,它的ascii码是92,92的十六进制是5c,所以“\”的url编码就是%5c。那么汉字的url编码呢?很简单,看例子:“胡”的ascii码是-17670,十六进制是BAFA,url编码是“%BA%FA”。编码后数据格式如下:  

 name1=value1&name2=value2&name3=value3&name4=value4&...

 其中name是Form中定义的INPUT、SELECT或TEXTAREA等标置(Tag)名字,value是用户输入或选择的设置值。程序中需要对编码后的数据进行分析和解码。要分析这种数据流,CGI程序必须首先将数据流分解成一组组的名字/值对。这可以通过在输入流中查找下面的两个字符来完成: 
  每当找到字符“=”,标志着一个Form变量名字的结束;每当找到字符“&”,标志着一个Form变量值的结束。请注意输入数据的最后一个变量的值不以“&”结束。 一旦“名字/值对”分解后,还必须将输入中的一些特殊字符转换成相应的ASCII字符。这些特殊字符是:

  • +:将“+”转换成空格符; 
  • %xx:用其十六进制ASCII码值表示的特殊字符。根据值xx将其转换成相应的ASCII字符。

参考:https://blog.csdn.net/zqj6893/article/details/9101201

  • 1
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
CGI(Common Gateway Interface)是一种常见的Web编程技术,可以让Web服务器调用外部程序实现动态网页。本文将介绍如何使用C语言实现一个简单的通讯录管理系统。 首先,需要在Web服务器上配置好CGI环境。这里以Apache服务器为例,可以在httpd.conf文件中添加如下配置: ``` ScriptAlias /cgi-bin/ "/usr/local/apache2/cgi-bin/" <Directory "/usr/local/apache2/cgi-bin"> AllowOverride None Options None Require all granted </Directory> ``` 这样,可以将CGI程序存放在/usr/local/apache2/cgi-bin目录下,并在Web页面中通过访问http://localhost/cgi-bin/program.cgi的方式调用程序。 接下来,编写C语言代码实现通讯录管理系统。这里使用了文件存储数据,因此需要先创建一个contacts.txt文件存放通讯录信息。 程序主要分为两部分:解析HTTP请求和处理通讯录操作。在解析HTTP请求时,需要读取请求方法、请求路径和请求参数等信息,然后根据请求路径调用相应的处理函数。在处理通讯录操作时,需要读取contacts.txt文件中的数据,并根据请求参数进行增删改查等操作。 以下是示例代码: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX_LINE 1024 // 解析HTTP请求 void parse_request(char *request_method, char *request_path, char *request_params) { char *request_body = getenv("QUERY_STRING"); if (request_body == NULL) { request_method[0] = '\0'; request_path[0] = '\0'; request_params[0] = '\0'; return; } sscanf(request_body, "%[^&]&%[^&]&%s", request_method, request_path, request_params); } // 处理添加联系人操作 void add_contact(char *params) { FILE *fp; char line[MAX_LINE]; fp = fopen("contacts.txt", "a"); if (fp == NULL) { printf("Content-type: text/plain\n\n"); printf("Failed to open file\n"); return; } sprintf(line, "%s\n", params); fputs(line, fp); fclose(fp); printf("Content-type: text/plain\n\n"); printf("Success"); } // 处理删除联系人操作 void delete_contact(char *params) { FILE *fp1, *fp2; char line[MAX_LINE]; int found = 0; fp1 = fopen("contacts.txt", "r"); if (fp1 == NULL) { printf("Content-type: text/plain\n\n"); printf("Failed to open file\n"); return; } fp2 = fopen("temp.txt", "w"); if (fp2 == NULL) { printf("Content-type: text/plain\n\n"); printf("Failed to open file\n"); fclose(fp1); return; } while (fgets(line, MAX_LINE, fp1) != NULL) { if (strstr(line, params) == NULL) { fputs(line, fp2); } else { found = 1; } } fclose(fp1); fclose(fp2); if (found) { remove("contacts.txt"); rename("temp.txt", "contacts.txt"); printf("Content-type: text/plain\n\n"); printf("Success"); } else { remove("temp.txt"); printf("Content-type: text/plain\n\n"); printf("Contact not found"); } } // 处理修改联系人操作 void update_contact(char *params) { FILE *fp1, *fp2; char line[MAX_LINE]; int found = 0; fp1 = fopen("contacts.txt", "r"); if (fp1 == NULL) { printf("Content-type: text/plain\n\n"); printf("Failed to open file\n"); return; } fp2 = fopen("temp.txt", "w"); if (fp2 == NULL) { printf("Content-type: text/plain\n\n"); printf("Failed to open file\n"); fclose(fp1); return; } while (fgets(line, MAX_LINE, fp1) != NULL) { if (strstr(line, params) == NULL) { fputs(line, fp2); } else { found = 1; sprintf(line, "%s\n", params); fputs(line, fp2); } } fclose(fp1); fclose(fp2); if (found) { remove("contacts.txt"); rename("temp.txt", "contacts.txt"); printf("Content-type: text/plain\n\n"); printf("Success"); } else { remove("temp.txt"); printf("Content-type: text/plain\n\n"); printf("Contact not found"); } } // 处理查询联系人操作 void query_contact(char *params) { FILE *fp; char line[MAX_LINE]; int found = 0; fp = fopen("contacts.txt", "r"); if (fp == NULL) { printf("Content-type: text/plain\n\n"); printf("Failed to open file\n"); return; } while (fgets(line, MAX_LINE, fp) != NULL) { if (strstr(line, params) != NULL) { printf("Content-type: text/plain\n\n"); printf("%s", line); found = 1; break; } } fclose(fp); if (!found) { printf("Content-type: text/plain\n\n"); printf("Contact not found"); } } int main() { char request_method[MAX_LINE], request_path[MAX_LINE], request_params[MAX_LINE]; parse_request(request_method, request_path, request_params); // 根据请求路径调用相应的处理函数 if (strcmp(request_path, "/add") == 0) { add_contact(request_params); } else if (strcmp(request_path, "/delete") == 0) { delete_contact(request_params); } else if (strcmp(request_path, "/update") == 0) { update_contact(request_params); } else if (strcmp(request_path, "/query") == 0) { query_contact(request_params); } else { printf("Content-type: text/plain\n\n"); printf("Invalid request"); } return 0; } ``` 编译并将程序命名为program.cgi,然后将其存放在/usr/local/apache2/cgi-bin目录下。此时,在Web页面中访问http://localhost/cgi-bin/program.cgi/add?name=John&phone=123456789即可添加联系人,访问http://localhost/cgi-bin/program.cgi/query?name=John即可查询联系人信息,以此类推。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值