《JxWeb服务器》之CGI模块
来源:互联网 发布:淘宝卖gv资源的店子 编辑:程序博客网 时间:2024/05/29 11:44
网上很多CGI教程,却很少有关于当自己写的Web服务器怎么支持CGI的教程,接下来就是讨论这方面的知识。(本人水平有限,如有错误,望指教)
CGI的全称是Common Gateway Interface——通用网关接口。
简单来讲:CGI程序是服务器上的一个可执行程序,Web服务器收到客户端的请求(以Post或者Get方式,其中url指向服务器某个CGI程序),服务器运行请求中url指向的CGI程序,并将请求中附带的参数通过某种方式传递给CGI进程,然后服务器将CGI返回的数据返回给客户端。
所以Web服务器处理CGI的步骤为:
1、收到客户端的请求。
2、运行请求中url指向的CGI可执行程序。
3、将请求中附带的参数传递给CGI进程。
4、读取CGI进程输出的数据。
5、检查数据的合法性,并将其返回给客户端。
注意:由于篇幅原因,本文主要讨论2、3、4步的实现。
Q:Web服务器通过什么方式将参数传给CGI程序?
具体分GET和POST两种情况:
1、GET请求中,服务器通过设置环境变量“QUERY_STRING”来传递给CGI进程。
在CGI进程中通过下面代码来取值:
char*p=getenv("QUERY_STRING");
注意:Get方式的参数是附带在url后面的(参数以Key=Value形式,多个参数用&隔开)。例如:http://127.0.0.1/cgi-bin/test.cgi?Key1=Value1&Key2=Value2 。
所以Web服务器可以这样来设环境变量:
char str[MAX_SIZE]; ... //省略str从上例url中获得参数"Key1=Value1&Key2=Value2"的过程。setenv("QUERY_STRING",str,1);
2、POST请求中,服务器通过给CGI进程的标准输入STDIN写数据来传递的,并且将字符总数设置给环境变量CONTENT_LENGTH。
在CGI进程中通过下面代码来取值:
char str[MAX_SIZE];n= atoi(getenv("CONTENT_LENGTH"));if(n){scanf("%s",str);}
注意:POSE方式的参数是附带在数据报里面,格式同前
所以Web服务器可以这样来设环境变量:
char buf[MAX_SIZE]; char str[MAX_SIZE];... //省略buf从上例url中获得参数"Key1=Value1&Key2=Value2"的过程。sprintf(buf,"%d",strlen(str));setenv("CONTENT_LENGTH",buf,1);write(ipfd[1],str,strlen(str)); //ipfd[1]是子进程的标准输入Q:Web服务器如何调用CGI程序、如何给CGI进程的标准输入写数据、如何取得CGI进程的标准输出?
我们知道默认情况下fork+exec复制出来的子进程是会继承父进程的环境变量和文件描述符(除非设置了close_on_exec标志位)。利用这个特点,再加进程间的管道通信知识即可。
代码如下:
#include <cstdio>#include <cstdlib>#include <iostream>#include <unistd.h>#include <cstring>#include <sys/wait.h>using namespace std;#define BUFFER_SIZE 1024int main(int argc,char **argv){FILE *file;char str[BUFFER_SIZE]="k1=v1&k2=v2"; //这是客户端参数char buf[BUFFER_SIZE];int ipfd[2];int opfd[2];if(argc!=3){cout<<"please using in this way:CGI [-p or -g] [FILENAME]\n"; return 0;}if(!strcmp(argv[1],"-p")) //POST方式调用CGI{sprintf(buf,"%d",strlen(str));setenv("CONTENT_LENGTH",buf,1); //这里省略设置其他环境变量pipe(ipfd);//create a pipe pipe(opfd);pid_t pid=fork();if(pid==-1) return 0;else if(pid==0){dup2(ipfd[0],STDIN_FILENO); //将stdin重定向到管道读 dup2(opfd[1],STDOUT_FILENO);//将stdout重定向到管道写close(ipfd[1]); //exec前先关闭子进程用不到的fdclose(opfd[0]); //execlp(argv[2],(char *)NULL);}else{close(ipfd[0]);//把父进程用不到的关闭,以便判断子进程是否关闭close(opfd[1]);write(ipfd[1],str,strlen(str));close(ipfd[1]); //关闭管道,以便子进程结束读操作while(read(opfd[0],buf,BUFFER_SIZE))cout<<buf;close(opfd[0]);wait(0);//替子进程收尸}}else if (!strcmp(argv[1],"-g")) //GET方式调用CGI{setenv("QUERY_STRING",str,1);pipe(opfd);pid_t pid=fork();if(pid==-1) return 0;else if(pid==0){ dup2(opfd[1],STDOUT_FILENO);//将stdout重定向到管道写close(opfd[0]); //exec前先关闭子进程用不到的fdexeclp(argv[2],(char *)NULL);}else{close(opfd[1]);//把父进程用不到的关闭,以便判断子进程是否关闭while(read(opfd[0],buf,BUFFER_SIZE))cout<<buf;close(opfd[0]);wait(0);//替子进程收尸}}return 0;}
实际开发中记得设置下面的环境变量以供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程序的路径名。
QUERY-STRING:表单输入的数据,URL中问号后的内容。
REMOTE-HOST:发送程序的主机名,不能确定该值。
REMOTE-ADDR:发送程序的机器的IP地址。
REMOTE-USER:发送程序的人名。
CONTENT-TYPE:POST发送,一般为application/xwww-form-urlencoded。
CONTENT-LENGTH:POST方法输入的数据的字节数。
- 《JxWeb服务器》之CGI模块
- cgi服务器
- PHP5模块和CGI
- perl CGI模块安装
- apache CGI模块应用
- Python CGI 模块剖析
- CGI原理解析系列之三----CGI如何完整获取WEB服务器数据
- Apache服务器技术之CGI环境变量和POST原理
- PHP在各种HTTP服务器上运行模式分析(CGI模式与模块模式)
- CGI、服务器内置模块、FastCGI、php-fpm的区别和详解
- CGI、服务器内置模块、FastCGI、php-fpm的区别和详解
- 网页服务器开发:CGI
- apache中添加cgi模块
- CGI CLI 与 模块模式
- Python之服务器模块设计学习
- web服务器之mongoose:核心处理模块
- CGI脚本服务器环境配置
- 服务器CGI模式的运行机制
- 未选择的路
- x&(-x) Lowbit(x)
- 2011-09-05 java多线程,起步遇困难
- Reentrancy
- joj2658
- 《JxWeb服务器》之CGI模块
- 注册Jdbc驱动程序的三种方式
- vi学习_1启动、停止
- Oracle与SAP两种ERP六维度比拼
- SQL取m到n条数据;数据库分页
- CString与int、char*、char[100]之间的转换
- 获得IPhone手机的相关硬件和其版本支持的SDK信息
- 【易语言】投递窗口消息(后台按键)DLL命令
- linux 忘记root密码的解决办法