个人主页:东洛的克莱斯韦克-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博客
伪代码示例
#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
{
}
}
}
版权归原作者 东洛的克莱斯韦克 所有, 如有侵权,请联系我们删除。