boa服务器实现温湿度显示,boa服务器实现CGI功能

CGI简介

CGI 是Web 服务器运行时外部程序的规范,按CGI 编写的程序可以扩展服务器功能。CGI 应用程序能与浏览器进行交互,还可通过数据库API 与数据库服务器等外部数据源进行通信,从数据库服务器中获取数据。格式化为HTML文档后,发送给浏览器,也可以将从浏览器获得的数据放到数据库中。几乎所有服务器都支持CGI,可用任何语言编写CGI,包括流行的C、C ++、VB 和Delphi 等。CGI 分为标准CGI 和间接CGI两种。标准CGI 使用命令行参数或环境变量表示服务器的详细请求,服务器与浏览器通信采用标准输入输出方式。间接CGI 又称缓冲CGI,在CGI 程序和CGI 接口之间插入一个缓冲程序,缓冲程序与CGI 接口间用标准输入输出进行通信。

简而言之:CGI就是web服务器可以调用的其他程序,该程序将输出重定向,在该程序中通过printf生成html,通过管道将数据发给web服务器,完成交互。

boa CGI实现

1.boa获取到数据时,执行process_requests()-->读取http头read_header()--->process_header_end();根据头部信息,获取到该请求为CGI

2.执行init_cgi()

int init_cgi(request * req)

{

int child_pid;

int pipes[2];

int use_pipes = 0;

SQUASH_KA(req);

if (req->is_cgi) {

if (complete_env(req) == 0) {        //设置环境变量

return 0;

}

}

#ifdef FASCIST_LOGGING

{

int i;

for (i = 0; i < req->cgi_env_index; ++i)

fprintf(stderr, "%s - environment variable for cgi: \"%s\"\n",

__FILE__, req->cgi_env[i]);

}

#endif

if (req->is_cgi == CGI || 1) {

use_pipes = 1;                //使用管道

if (pipe(pipes) == -1) {

log_error_time();

perror("pipe");

return 0;

}

/* set the read end of the socket to non-blocking */

if (set_nonblock_fd(pipes[0]) == -1) {        //设置读管道为非阻塞

log_error_time();

perror("cgi-fcntl");

close(pipes[0]);

close(pipes[1]);

return 0;

}

}

child_pid = fork();        //创建子进程,用于启动cgi程序,程序执行完成后退出boa

switch(child_pid) {

case -1:

/* fork unsuccessful */

log_error_time();

perror("fork");

if (use_pipes) {

close(pipes[0]);

close(pipes[1]);

}

send_r_error(req);

/* FIXME: There is aproblem here. send_r_error would work

for NPH and CGI, but not for GUNZIP. Fix that. */

/* i'd like to send_r_error, but.... */

return 0;

break;

case 0:

/* child */

if (req->is_cgi == CGI || req->is_cgi == NPH) {

char *foo = strdup(req->pathname);

char *c;

if (!foo) {

WARN("unable to strdup pathname for req->pathname");

_exit(1);

}

c = strrchr(foo, '/');

if (c) {

++c;

*c = '\0';

} else {

/* we have a serious problem */

log_error_time();

perror("chdir");

if (use_pipes)

close(pipes[1]);

_exit(1);

}

if (chdir(foo) != 0) {

log_error_time();

perror("chdir");

if (use_pipes)

close(pipes[1]);

_exit(1);

}

}

if (use_pipes) {

close(pipes[0]);

/* tie cgi's STDOUT to it's write end of pipe */

if (dup2(pipes[1], STDOUT_FILENO) == -1) {        //将写管道重定向到标准输出,在cgi中使用printf,数据就会被发送到管道中

log_error_time();

perror("dup2 - pipes");

close(pipes[1]);

_exit(1);

}

close(pipes[1]);

if (set_block_fd(STDOUT_FILENO) == -1) {        //设置管道为阻塞

log_error_time();

perror("cgi-fcntl");

_exit(1);

}

} else {

/* tie stdout to socket */

if (dup2(req->fd, STDOUT_FILENO) == -1) {

log_error_time();

perror("dup2 - fd");

_exit(1);

}

/* Switch socket flags back to blocking */

if (set_block_fd(req->fd) == -1) {

log_error_time();

perror("cgi-fcntl");

_exit(1);

}

}

/* tie post_data_fd to POST stdin */

if (req->method == M_POST) { /* tie stdin to file */

lseek(req->post_data_fd, SEEK_SET, 0);

dup2(req->post_data_fd, STDIN_FILENO);

close(req->post_data_fd);

}

/* Close access log, so CGI program can't scribble

* where it shouldn't

*/

close_access_log();

/*

* tie STDERR to cgi_log_fd

* cgi_log_fd will automatically close, close-on-exec rocks!

* if we don't tied STDERR (current log_error) to cgi_log_fd,

* then we ought to close it.

*/

if (!cgi_log_fd)

dup2(devnullfd, STDERR_FILENO);

else

dup2(cgi_log_fd, STDERR_FILENO);

if (req->is_cgi) {

char *aargv[CGI_ARGC_MAX + 1];

create_argv(req, aargv);

execve(req->pathname, aargv, req->cgi_env);        //启动cgi程序

} else {

if (req->pathname[strlen(req->pathname) - 1] == '/')

execl(dirmaker, dirmaker, req->pathname, req->request_uri,

NULL);

#ifdef GUNZIP

else

execl(GUNZIP, GUNZIP, "--stdout", "--decompress",

req->pathname, NULL);

#endif

}

/* execve failed */

WARN(req->pathname);

_exit(1);

break;

default:

/* parent */

/* if here, fork was successful */

if (verbose_cgi_logs) {

log_error_time();

fprintf(stderr, "Forked child \"%s\" pid %d\n",

req->pathname, child_pid);

}

if (req->method == M_POST) {

close(req->post_data_fd); /* child closed it too */

req->post_data_fd = 0;

}

/* NPH, GUNZIP, etc... all go straight to the fd */

if (!use_pipes)

return 0;

close(pipes[1]);

req->data_fd = pipes[0];            //保存读管道的fd

req->status = PIPE_READ;            //状态置为PIPE_READ

if (req->is_cgi == CGI) {

req->cgi_status = CGI_PARSE; /* got to parse cgi header */

/* for cgi_header... I get half the buffer! */

req->header_line = req->header_end =

(req->buffer + BUFFER_SIZE / 2);

} else {

req->cgi_status = CGI_BUFFER;

/* I get all the buffer! */

req->header_line = req->header_end = req->buffer;

}

/* reset req->filepos for logging (it's used in pipe.c) */

/* still don't know why req->filesize might be reset though */

req->filepos = 0;

break;

}

return 1;                //more to do

}3.下一次轮询中,程序回到process_request,状态为

PIPE_READ,准备读取管道中的数据。读取后,继续轮询,直至全部读取完毕,状态置为

PIPE_WRITE,将数据发送给客户端。(正是由于boa的这种轮询机制,使得它可以处理多个请求而不会卡住)

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值