由于Carl要用到我的程序,我们便合作工作。但是他写的程序是Python的,我写的程序是Java的,必须得找一种方式进行通信。尽管有Jython这些东西,但是Carl认为还是CGI最简便。于是,前阵子开始学学CGI怎么弄。刚开始,觉得好像也不是很难,但是后来进展没有预期的顺利。最后,由于学院的服务器有CGI模块但是不允许随便跑CGI,实验室服务器又装的是FastCGI,感觉麻烦,最后Carl说还是用socket吧... - - |||。

整体来说,用CGI进行通信这个计划算是破产了。虽然是很老旧、基本都不会再用的东西了,但是由于对我来说是新东西,还是很好奇,没有实现,自然是一种惋惜。虽然最后没能用上CGI,但是个人觉得如果学院服务器让用户自己跑CGI的话,应该还是没问题的。无论怎样,还是记录下一些基本知识,免得以后又忘了。

CGI年代久远,不过却实现了动态网页。CGI,准确说,应该是种协议(或者说接口),它使得server中的程序(cgi script)能够通过标准I/O流(STDIN和STDOUT,比如在Java语言里就是System.in和System.out,在C里面就是printf等,只要是能够进行标准I/O流读写的程序,都可以用来实现CGI)读取到所需的信息和输出信息给浏览器,而这些所要从客户端读取的信息则是包含在某些已经被定义好的环境变量中,我们只需要读取这些环境变量,自然就能获取想要的值了(这也就是CGI这个借口为我们所做的事)。而通常所说的CGI,也有可能泛指CGI程序,即CGI script,是开发者自己所写的、处理用户请求的程序。
        总体来说,过程是这样的:

1. 服务器接受到请求
        2. 服务器发现这个请求是需要一个CGI程序来进行处理
        3. 服务器建立一个环境,这个运行环境里有一些变量,也就是所谓的CGI程序所需要的环境变量
        4. 服务器在这个环境下启动相应的CGI程序
        5. CGI程序解析自己想要的环境变量来获取所提交的请求信息
        6. CGI程序对这些请求信息做相应的处理
        7. CGI程序将相应的结果输出到标准输出STDOUT,此结果将被输出到用户端,呈现给用户结果。
        8. CGI程序执行完毕,退出程序。

比较详细来说,原理大概是这样的:
       1. 客户端在浏览某个网页的时候,提交表单(form)。而表单的action则指定了要处理该表单的CGI程序,比如:

                   <html>
<body>
<form action="/cgi-bin/plus.cgi" method="GET">
<input name="m" size="5">
<input name="n" size="5"><br>
<input type="submit" values="提交">
</form>
</body>
</html>

上面的程序中,action="/cgi-bin/plus.cgi" 的意思就是说“这个表单里的数据,都交给plus.cgi这个程序处理了,然后它处理完这些数据后,再把结果返回给浏览器”。
         需要说明的是,plus是一个可执行文件的文件名,比如可能是一个shell文件(例如 plus.sh),其后缀不一定是.cgi。那么为什么要取在这里取名.cgi呢?原因是这样能说明,这个表单处理,是通过一个类型为cgi的程序进行处理,或者说,通过cgi这种方式让这个可执行文件对提交的数据进行处理。一般来说,出于安全考虑,不是任何用户都有权限去写一个自己的cgi程序然后上传到服务器、让该服务器去运行的(比如我们学院的服务器就不行,哎...)。而只有放在服务器指定目录(一般为cgi-bin)下的可执行文件,才会被被视为是cgi程序,才能被执行。而一般人是无法访问这个目录的。
        
        2. 然后,name为“m”和“n”的这两个变量以及他们的值,就通过某个环境变量输入到CGI程序中,由CGI程序去进行该CGI程序所指定的处理了。GET和POST获取“m”和“n”的方式有所不同。如果提交方法是GET的话,那么GET所提交的内容则被包含在名为QUERY_STRING的环境变量中,当得到这个环境变量的值后,将其内容解析出来就可以得到name/value这样的值对了,就可以进行相应的处理了。而POST的话,则需要从标准输入流STDIN里面读取数据,而这些数据到底有多少呢?这个则需要通过读取CONTENT_LENGTH这个环境变量的值来知道。
        像在C语言里面,可以通过getenv函数来直接获取环境变量的值,比如:getenv("QUERY_STRING"),  getenv("CONTENT_LENGTH")等等。Perl可能要算是写CGI的最佳语言,但是不会Perl,此处略过。另外,由于我的程序是用Java写的,就使得读取环境变量的方式有点特殊,因为Java是没有直接获取这些环境变量的函数的。Java为何不能直接访问环境变量?简单说,因为Java内部还有一个属于System这个类的属性。因此,我们一个System.getProperty获取的是Java中这个System类的属性的,而不是环境变量的。这些System的属性也是以name/value这样的形式来存储一些Java运行环境的信息的。因而,额外的环境变量(或者说属性信息)需要用指令java -D的形式,详见后面的wrapper程序。

常用的环境变量有:REQUEST_METHOD,QUERY_STRING,CONTENT_LENGTH,PATH_INFO。其他的有:SERVER_SOFTWARE,SERVER_NAME,GATEWAY_INTERFACE,SERVER_PROTOCOL,SERVER_PORT,PATH_TRANSLATED,SCRIPT_NAME,REMOTE_HOST,REMOTE_ADDR,AUTH_TYPE,REMOTE_USER,REMOTE_IDENT,CONTENT_TYPE。如果现在忘记这些是干嘛的了...额...google下吧...

现在,我们已经读取到了所想要的环境变量。但是,这些环境变量的值,是需要我们进行解析的,因为当初在传给我们的时候,就是进行了URL编码的(URL encode)。比如,如果我们提交的表单是GET类型的话,再提交完信息后,可以在地址栏看来类似这样的url地址:http://www.xxxxxxx.edu/cgi-bin/plus.cgi?m=5&n=6。其中,“m=5&n=6”就是被编码的字符串,也就是我们想要获取的值。而“http://www.xxxxxxx.edu/cgi-bin/plus.cgi”是处理该表单的cgi程序的地址。“?”说明后面的字符串(即“m=5&n=6”)是传入的参数。不难看出,在编码的时候,类似于这样的规则“name1=value1&name2=value2&name3=value3”。此外,非西文的字符串将被“%XX”所代替,空格将被“+”代替。具体地,去参考URL encode的相关资料。
       如何解析这些麻烦的字符串,不需要自己再动手去写,网上有很多这样的函数库,各种语言。直接用网上现成的函数库来解析就行了。就Java来说,推荐cgi_lib.java这个库。很方便,应用也很广泛,文件也很小。其中函数的功能是跟cgi_lib.pl一样的。

3. 解析字符串后,我们可以知道变量m的值为5,变量n的值为6。然后就可以在CGI程序中进行相应的处理了。自己想怎么处理就怎么处理。比如,此处是想处理加法,则在自己的CGI程序里实现m和n的加法即可。

4. 处理完了数据,需要将结果呈现给浏览器端的用户。这个简单,直接用STDOUT就行了。比如,C语言用printf,Java语言用System.out.println之类的。但是需要注意的是,首先输出的必须是"Content-type: text/plain"(也就是MIME头信息,告诉server它随后的输出是以纯ASCII文本的形式),然后下面空一行(必须空一行),再直接打印出要呈现给用户的html语句。比如,在Java里面,就是:

        System.out.println("Content-type: text/plain");
System.out.println("");

比如,要测验自己是否有权限可以写一个CGI放在服务器上运行,则可以写一个最简单的CGI程序,该程序暂时不处理任何来自用户的请求,只是输出"Hello, world"。
        shell程序可以写成:

        #!/bin/sh
echo "Content-type: text/html"
echo ""
echo "<html>"
echo "<body>"
echo "<h1>Hello, world</h1>"
echo "</body>"
echo "</html>"

C语言可以写成:

        #include<stdio.h>
void main(void){
printf("Content-type: text/html\n");
printf("\n");
printf("<html>\n");
printf("<body>\n");
printf("<h1>Hello, world</h1>\n");
printf("</body>");
printf("/<html>");
}

这样,在客户端运行就会呈现出<h1>大小的“Hello, world”了。

Java的特别注意:
        1.Java读取环境变量,只能通过-D的option来加以读取。
        2.Java生成的.class文件(比如java_plus.class),这不是一个通常意义上的可执行文件,这个文件只是说通过JVM可以执行起来。而CGI程序是一个直接可以执行的文件。因此,我们需要写一个wrapper,将这个.class文件封装起来。当调用这个wrapper程序的时候,这个wrapper程序能通过Java指令运行该.class文件。
        结合上诉两点,则我们可以写一个shell文件当做wrapper程序,如下:

        #!/bin/sh
java \
-Dcgi.content_type=$CONTENT_TYPE \
-Dcgi.content_length=$CONTENT_LENGTH \
-Dcgi.request_method=$REQUEST_METHOD \
-Dcgi.query_string=$QUERY_STRING \
-Dcgi.server_name=$SERVER_NAME \
-Dcgi.server_port=$SERVER_PORT \
-Dcgi.script_name=$SCRIPT_NAME \
-Dcgi.path_info=$PATH_INFO \
java_plus

然后将上面的文件保存为plus.sh,并且放在指定的目录(比如cgi-bin)即可。这样,当表单提交新的时候,就会到这个目录中(因为后缀名为cgi)去寻找名为plus的文件,然后执行这个文件。而在java_plus这个文件中,我们用System.getProperty("cgi.query_string")就可以访问到QUERY_STRING这个环境变量了。

推荐一些链接:
http://www.jmarshall.com/easy/cgi/

http://www.eli.sdsu.edu/courses/spring96/cs596/notes/andrew/cgi.html

http://www.javaworld.com/javaworld/jw-01-1997/jw-01-cgiscripts.html

http://apps.hi.baidu.com/share/detail/18814484

http://www.jaguarpc.com/forums/showthread.php?t=2553

http://httpd.apache.org/docs/current/howto/cgi.html

至于FastCGI,这个效率比传统CGI高很多。但是,比较麻烦,需要用循环,还要设置端口什么的,就没动手搞那个,只是看了下相关资料。还是放在这里吧。

http://www.phpchina.com/download/handbook/linux-html/1272.html

http://www.20cn.net/ns/wz/net/data/20030615005558.htm

http://www.fastcgi.com/devkit/doc/fcgi-java.htm

http://www.citycat.ru/doc/FastCGI/fcdk/index.html

http://hi.baidu.com/coffeefoam/blog/item/1446493be749f3e814cecbb8.html

转: https://blog.csdn.net/hungryhuang/article/details/6601684

转-编写CGI小结的更多相关文章

  1. 编写CGI程序步骤

    CGI common gateway interface 可以让一个客户端,从网页浏览器向服务器请求数据, 这是描述客户端和服务器程序之间传输数据的一种标准. CGI是运行在服务器上的程序,提供同客户 ...

  2. shell脚本--编写CGI代码(shell结合html)以及环境变量

    实现shell和html标签混合的方式编写代码: 推荐  初始CGI ,看完大概之后,大概对cgi有个大体的印象.下面是编写混合代码的示例: #!/bin/bash #index.cgi echo & ...

  3. Perl &amp; Python编写CGI

    近期偶然玩了一下CGI,收集点资料写篇在这里留档. 如今想做HTTP Cache回归測试了,为了模拟不同的响应头及数据大小.就须要一个CGI按须要传回指定的响应头和内容.这是从老外的測试页面学习到的经 ...

  4. Linux环境下使用perl编写CGI(httpd)

    例子1: /var/www/cgi-bin/hello.cgi #!/usr/bin/perl print "Content-type: text/html\n\n"; print ...

  5. Linux环境下使用C/C++编写CGI(httpd)

    step1下载: ftp://ftp.gnu.org/gnu/cgicc/ step2: tar xzf cgicc-X.X.X.tar.gz(用最新版本) cd cgicc-X.X.X ./conf ...

  6. EasyWebServer编写CGI程序的环境变量

    示例: SERVER_SOFTWARE=EasyWebServer/1.9 SERVER_PROTOCOL=HTTP/1.1 SERVER_PORT= SERVER_NAME=aozima-noteb ...

  7. 使用c语言编写cgi程序

    http://blog.chinaunix.net/uid-22566367-id-3109877.html 简单的说,cgi是沟通HTML表单和服务器端程序的接口,是可以被其他语言所应用的一个规范集 ...

  8. 关于chrome插件编写的小结

    一个插件的大致目录结构如下: 其中manifest文件最为重要,它定义/指明插件应用的相关信息(权限.版本.功能说明等),点此查看Manifest的详情>>   这里有一篇chrome官方 ...

  9. Linux环境下使用shell编写CGI(httpd)

    /var/www/cgi-bin/hello.sh #!/bin/bash echo "Content-type: text/html" echo "" ech ...

随机推荐

  1. Springboot 1.5.x 集成基于Centos7的RabbitMQ集群安装及配置

    RabbitMQ简介 RabbitMQ是实现了高级消息队列协议(AMQP)的开源消息代理软件(亦称面向消息的中间件). RabbitMQ是一套开源(MPL)的消息队列服务软件,是由LShift提供的一 ...

  2. Java 的Event机制浅析

    https://blog.csdn.net/kehyuanyu/article/details/23540901

  3. linux相关操作命令

    1.复制文件:cp -r file ./src 2.删除文件:rm -rf file 3.解压文件:tar -xvf bianque.tar.gz

  4. EF 下如何更新数据表数据

    转载请注明出处:http://www.cnblogs.com/zhiyong-ITNote/ 一直不习惯linq的扩展方法,每次用的时候,贼不顺手,尤其是查数据的时候,这不更新个数据库这么简单地需求都 ...

  5. 【三边定位】 演示程序V0.1

    忙于工作,这个小东西一直没有空去弄, 最近简单修改了些算法, 精度还有待提高. 贴一张图片 坐上角的坐标是鼠标点(31,17),后面location 是三边定位算出来的(31,19),后面跟的erro ...

  6. 嵌入式单片机STM32应用技术(课本)

    目录SAIU R20 1 6 第1页第1 章. 初识STM32..................................................................... ...

  7. 南方IT学校期末PCB结课项目考试(实操)说明书

    南方IT学校期末结课项目考试(实操)说明书(一) 课程:<印制电路板设计技术>(二) 项目:笔记本电脑电源适配器的印制电路板设计(三) 背景说明:如今笔记本已经进入千家万户,作为给电脑充电 ...

  8. VUE学习第一天,安装

    vue生命周期好文章: http://www.zhimengzhe.com/Javascriptjiaocheng/236707.html

  9. DAG 上的动态规划(训练指南—大白书)

    有向无环图(DAG,Directed Acyclic Graph)上的动态规划是学习动态规划的基础.很多问题都可以转化为DAG上的最长路.最短路或路径计数问题. 一.矩形嵌套 题目描述:       ...

  10. JavaScript之中Array用法的一些技巧总结

    1.创建一个全部为0,长度为100的数组(ES6) Array(10).fill(0) 2.创建一个长度为100的数组,其中保存0 ~ 99 let array = Array(100).fill(0 ...