【网络】详解HTTP协议的CGI机制和CGI进程

东洛的克莱斯韦克 2024-10-05 13:37:09 阅读 70

目录

引言

CGI机制模型

伪代码示例


个人主页:东洛的克莱斯韦克-CSDN博客

引言

CGI机制是HTTP协议提供的偏底层的一套机制,也是非常重要的机制——它让大量的业务进程和HTPP协议解耦。而CGI进程是业务层的,用来处理各种数据,比如把用户提交上来的数据插入数据库,再比如做某种运算。

CGI机制和CGI进程在概念上是完全不一样的,他们的关系就行老婆和老婆饼一样。

客户端通过HTTP协议向服务器提交数据的方式主要有两种:

1.GET方法请求,GET方法没有请求正文,一般用来拉取服务器的数据,但也可以通过URL的参数提交数据(URL中 ?分隔符后面的就是要提交的数据)

2.POST方法请求,通过请求正文向服务器提交数据

不同的方法的请求,提交的数据量不一样,HTTP底层的CGI机制在处理上也会不一样。

CGI机制模型

简单来说处理HTTP协议请求和响应的服务是父进程,当客户端提交数据给服务器时,HTTP服务会让子进程进行CGI程序替换(让子进程执行exec系列的系统调用),此时子进程就是CGI进程。

【linux】进程间通信(IPC)——匿名管道,命名管道与System V内核方案的共享内存,以及消息队列和信号量的原理概述_linux ipc-CSDN博客父子进程可以用系统提供的进程间通信的方案完成数据的传输。

可以参考小编如下方案

【Linux系统编程】子进程被程序替换后,如何保持父子进程的通信-CSDN博客

伪代码示例

<code>#define ENV "url_parameter" // 环境变量的k值 ,GET方法的请求的参数通过环境变量传给子进程

#define ENV_M "request_method" // 环境变量,请求的方法

#define ENV_L "request_len" // 环境变量,正文的长度

#define ERR_H "wwwroot/err.html" // 返回错误页面的路径

void cgi_dispose_request_y() // 用CGI机制处理数据

{

// LOG(INFO, "进入CGI机制的函数了...");

// 建立信道,相对于父进程来说

int r_channel[2] = {-1, -1}; // 读信道

int w_channel[2] = {-1, -1}; // 写信道

if (0 != pipe(r_channel) || 0 != pipe(w_channel)) // 创建匿名管道

{

}

// 创建子进程

pid_t id = fork();

if (id == 0) // 子进程

{

close(r_channel[0]);

close(w_channel[1]);

if (setenv(ENV_M, _http_q._method.c_str(), 1) == -1)

{

);

}

if (setenv(ENV_L, (std::to_string(_http_q.body_line)).c_str(), 1) == -1)

{

);

}

// 在程序替换之前,需要把子进程的读信道和写信道分别重定向到标准输入0,标准输出1中

if (_http_q.if_url_parameter) // url带参说明它是一个GET请求,用环境变量传递数据

{

if (setenv(ENV, _http_q._url_parameter.c_str(), 1) == -1)

{

}

}

// LOG(INFO, "环境变量添加完毕");

dup2(w_channel[0], 0); // 0号文件描述符,从信道里读

dup2(r_channel[1], 1); // 1号文件描述符,向信道里写

// 代码和数据均会被替换,但内核数据不会被替换,包括文件描述符

if (execl(_http_q._url_path.c_str(), _http_q._url_path.c_str(), nullptr) == -1)

{

}

}

else if (-1 == id)

{

}

else // 父进程

{

close(r_channel[1]);

close(w_channel[0]);

if (_http_q.if_url_parameter == false) // url不带参,在这里说明该请求是一个POST请求

{

int max = _http_q.body_line;

for (int i = 0; i < max; i++)

{

write(w_channel[1], &_http_q.request_body[i], 1); // 把请求正文写入管道

}

}

char ch = 'x';

while (read(r_channel[0], &ch, 1) == 1) // 死循环读取数据,管道没有数据阻塞,子进程发送数据完毕退出,文件描述符也会关闭,父进程就会读0,然后退出循环

{

_http_p.response_body += ch;

}

close(r_channel[0]); // 关闭文件描述符,在网络通信中,文件描述符也是一种很重要的资源

close(w_channel[1]);

int code; // 子进程的退出状态

waitpid(id, &code, 0);

if (WIFEXITED(code)) // 如果子进程是正常退出

{

}

else

{

}

}

}



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。