HTTP服务器(三)

2023-11-15

下面实现处理动态页面的逻辑:

  • 创建一对命名管道,fork创建子进程;让父子进程执行不同的任务

值得注意的是,由于管道数据流动是单向的,所以要创建一对;父进程将必要的信息通过管道传递给子进程,子进程将计算的结果通过管道传递给父进程。

int HanndlerCGI(int sock, Req* req)
{
    err_code = 200;
    //1、创建一对匿名管道
    int fd1[2], fd2[2];
    pipe(fd1);
    pipe(fd2);
    int father_read = fd1[0];
    int child_write = fd1[1];
    int father_write = fd2[1];
    int child_read = fd2[0];
    //2、创建子进程
    int ret = fork();
    if(ret > 0)                                                                                                                      
    {
        //   1)父进程流程
        close(child_write);
        close(child_read);
        HandlerCGIFather(sock, father_read, father_write, req, ret);                                                                 
    }
    else if(ret == 0)
    {
        //   2)子进程流程
        close(father_read);
        close(father_write);
        HandlerCGIChild(sock, child_read, child_write, req);
    }
    else
    {
        perror("fork");
        err_code = 404;
    }
    return err_code;
}                                                                                                                                    
  • 父进程将必要的信息传递给子进程,构造响应报文,将子进程计算生成的页面发送给客户端

传递信息给子进程:

如果是post方法,需要将body中的内容通过管道发送给子进程;

如果是get方法,query_string已经在之前获取到了,不需要作什么了。

构造响应报文:

由于将生成动态页面的任务交给了子进程,所以父进程只需要构造响应报文,将子进程通过管道传递给父进程的内容,发送给客户端。

void HandlerCGIFather(int sock, int father_read, int father_write, Req* req, int pid)
{
    printf("in CGIFather\n");
    //1.如果是post请求,将body中的数据写到管道中,由子进程完成动态页面的生成
    if(strcmp(req->method, "POST") == 0)
    {
        char buf[1024] = {0};
        read(sock, buf, req->content_length);
        write(father_write, buf, req->content_length);
    }
    //2.构造HTTP响应
    const char* first_line = "HTTP/1.1 200 OK\n";
    const char* blank_line = "\n";
    send(sock, first_line, strlen(first_line), 0);                                                                                   
    send(sock, blank_line, strlen(blank_line), 0);
    //3.从管道中读取数据(子进程动态生成的页面),写到socket中
    char c = '\0';
    while(read(father_read, &c, 1) > 0)
    {                                                                                                                                
        write(sock, &c, 1);
        printf("%c\n", c);
    }   
    printf("write to sock\n");
    //4.进行进程等待,回收进程资源
    waitpid(pid, NULL, 0);
}   
  • 子进程通过程序替换,生成结果,发送给父进程

设置环境变量:

由于,进行程序替换后,就无法知道父进程发送给子进程的数据了,于是我们就要想办法让程序替换后的程序仍旧可以获得这些数;又因为我们发现环境变量是进行程序替换后,仍旧可以访问到的,所以,我们要做的第一步就是将必要的信息设置成环境变量。

把标准输入和标准输出重定向到管道上:

这样一来,我们实现的CGI程序往标准输出上写,就是往管道上写;于是只要是能够访问标准输入输出,以及环境变量的编程语言就都可以实现CGI程序了。

获取CGI程序的真实路径,进行程序替换,让替换后的程序完成具体的计算过程。

void HandlerCGIChild(int sock, int child_read, int child_write, Req* req)
{
    printf("in CGIchild\n");
    //1、设置环境变量
    char method[1024], query_string[1024], content_length[1024];
    sprintf(method, "REQUEST_METHOD=%s", req->method);
    putenv(method);
    printf("method putenv:%s\n", method);
    if(strcmp(req->method, "GET") == 0)
    {
        sprintf(query_string, "QUERY_STRING=%s", req->query_string);
        putenv(query_string);
    }
    else                                                                                                                             
    {
        printf("put content_length : %d\n", req->content_length);
        sprintf(content_length, "CONTENT_LENGTH=%d", req->content_length);
        putenv(content_length);
    }                                                                                                                                
    printf("before dup\n");
    //2、把标准输入和输出重定向到管道上
    dup2(child_read, 0);
    dup2(child_write, 1);
    //3、进行程序替换
    //  a)拼装url为一个完整的文件路径
    char file_path[1024*4] = {0};
    HandlerFilePath(req->url_path, file_path);
    //  b)进行程序替换
    int err = execl(file_path, file_path, NULL);
    //4、如果exec失败,进行错误处理
    if(err < 0)
    {
        perror("execl error");
        exit(0);                                                                                                                     
    }
}
  • 实现一个CGI程序(计算两个数相加)

#include <stdio.h>                                                                                                                   
#include <string.h>
#include <stdlib.h>
int GetQueryString(char buf[])
{
    char* method = getenv("REQUEST_METHOD");
    if(strcmp(method, "GET") == 0)
    {   
        char* query_string = getenv("QUERY_STRING");
        if(query_string == NULL)
        {   
            fprintf(stderr, "get QUERY_STRING error\n");
        }   
        strcpy(buf, query_string);
        return 0;
    }   
    else if(strcmp("POST", method) == 0)
    {
        fprintf(stderr, "in post get string\n");                                                                                     
        char* content_len = getenv("CONTENT_LENGTH");
        fprintf(stderr, "cont—len:%s\n", content_len);
        int content_length = atoi(content_len);
        fprintf(stderr, "cont—length:%d\n", content_length);
        int i = 0;
        char c = '\0';
        while(i < content_length)
        {
            read(0, &c, 1);
            buf[i++] = c;
        }
        fprintf(stderr, "string:%s\n", buf);
        return 0;
    }
    return -1;                                                                                                                       
}
int main()
{
    fprintf(stderr, "in math\n");
    char query_string[1024*4] = {0};
    int ret = GetQueryString(query_string);
    if(ret < 0)
    {
        fprintf(stderr, "GetQueryString error\n");
        return 0;
    }
    fprintf(stderr, "query_string:%s\n", query_string);
    int a,b;
    sscanf(query_string, "a=%d&b=%d", &a, &b);
    fprintf(stderr, "after anylaze string\n");                                                                                       
    int sum = a+b;
    printf("<h1>sum = %d</h1>", sum);
    fprintf(stderr, "%d+%d=%d\n", a, b, sum);
}

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

HTTP服务器(三) 的相关文章

  • 监狱智能管理平台 ——监室点名(人脸识别)

    从事人脸识别行业渐进2年 主要开发监狱的人脸识别服务 内心一直有一个梦想 打造出一款智能化的现代化的监狱管理系统 不过要智能化到什么程度 心里却没有普尼 恐怕是从事IT行业后 总想设计出一款满意的产品 对自己从事该行业有一个交代做的怪吧 自
  • HTTP服务器(二)

    前面已经实现了服务器的整体框架 现在就来具体实现HTTP服务器处理静态页面的逻辑 要获取具体的静态文件 就要知道要获取的文件的路径 我们分析url 协议方案名 使用http 或https 等协议方案名获取访问资源时要指定的协议类型 登录信息
  • 项目上线后遇到的问题总结

    项目上线了 一堆堆的问题也随之出现了 除了时间比较匆忙导致没有细致的做验证之外 当初也确实没有在最重要的功能需求上把好关 导致后来要做很多的修改而弥补之前的错误 下面是上线后遇到的问题和解决办法总结 问题一 用户非正常流程导致的错误 用户注
  • 利用response对象实现下载文件功能

    HttpServletResponse对象继承了ServletResponse接口 下面利用response对象实现下载的功能 单个文件的下载 package com dongmu servlet import javax servlet
  • 使用java实现基础的家庭记账程序

    家庭记账程序 需求说明 具体操作 完整代码 总结 需求说明 1 该程序能够记录家庭的收入 支出 并能打印收支明细表 2 项目采用分级菜单的方式 主菜单如下 3 假设家庭起始的生活基本金为10000元 4 每次登记收入 菜单2 后 收入的金额
  • 服务器物理机使用ESXI虚拟化并划分虚拟机

    前言 最近因为增加了一台物理机 所以需要对物理机进行虚拟化后划分虚拟机 下面主要来介绍物理机划分虚拟机的操作步骤 物理机虚拟化 1 下载VMware VMvisor Installer 6 0 0 update01 3029758 x86
  • 解决element 弹窗屏幕变灰的问题(双层弹窗)(遮罩层问题)

    问题 新增按钮弹窗 新增按钮里需要选择部门 又一个弹窗 此时点第二个弹窗的时候页面会灰 解决 在最后一个弹窗上面加属性 append to body true 就能解决 element 已经说明了问题 嵌套Dialog必须指定该标签 这个属
  • SpringBoot+MyBatis搭建迷你小程序

    本项目如下 maven的安装目录在哪 setting文件放在哪 仓库在哪 分别为G Program Files x86 apache maven 3 5 4 conf 与G Program Files x86 apache maven 3
  • Java项目——文档搜索引擎

    文章目录 1 项目概述 2 准备阶段 2 1 项目创建 2 2 准备静态页面 3 搜索逻辑 4 分词 5 处理 HTML 文件 5 1 枚举文件夹中所有文件 5 2 预处理文件 5 2 1 获取标题 5 2 2 获取 URL 5 2 3 获
  • 【(项目)Web服务器的实现】——自主实现一个Web服务器项目,通过该服务器搭建个人网站(保姆级教程),可写在简历上

    个人主页 努力学习的少年 版权 本文由 努力学习的少年 原创 在CSDN首发 需要转载请联系博主 如果文章对你有帮助 欢迎关注 点赞 收藏 一键三连 和订阅专栏哦 目录 前言 一 项目介绍 1 什么是Web服务器 2 项目展示 二 认识ht
  • 电脑商城项目总结-01用户管理模块(注册,登录,修改密码,个人信息,上传头像)

    目录 部分图片展示 application properties 创建数据库并且验证是否静态资源能够正常访问 创建用户表 实体类 持久层 业务层 控制层 拦截器 单元测试 部分图片展示 以下是大体上的代码 application prope
  • 如果当前node.js版本和项目需要版本不一样,卸载重装其他版本node.js的方法

    其实这种node js版本不一样的问题 可以选择用nvm来管理node js的不同版本 此处仅总结卸载当前版本node js 重新安装所需版本node js的方法 另 现在 用Vite官网里面的 yarn npm等 的方法 创建Vue3项目
  • 项目 谷粒学院Day16-18

    Day 16 07 13 统计分析模块 后台 准备工作 创建统计表 创建service statistics模块 使用代码生成器生成代码 创建启动类 SpringBootApplication ComponentScan basePacka
  • 注释转换(C->C++)

    转换原理图解 基于上图原理 可以写出代码 主函数 define CRT SECURE NO WARNINGS 1 include
  • 初探Linq表达式和lambda表达式

    Linq表达式 LINQ 语言集成查询 LanguageIntegrated Query 是一组用于c 和Visual Basic语言的扩展 它允许编写C 或者VisualBasic代码以查询数据库相同的方式操作内存数据 博主认为 Linq
  • 计算机毕业设计-基于微信小程序高校学生课堂扫码考勤签到系统-校园考勤打卡签到小程序

    注意 该项目只展示部分功能 如需了解 评论区咨询即可 本文目录 1 开发环境 2 系统的设计背景 3 各角色功能模块 3 1 用户 3 2 管理员 4 系统页面展示 4 1 学生端功能模块展示 4 2 教师端功能模块展示 5 更多推荐 6
  • Springboot使用future异步获取ip地址对应的地理位置

    future介绍 Future代表的是异步执行的结果 意思是当异步执行结束之后 返回的结果将会保存在Future中 那么我们什么时候会用到Future呢 一般来说 当我们执行一个长时间运行的任务时 使用Future就可以让我们暂时去处理其他
  • Qt - 使用子目录项目来 配置多个子工程/子模块

    QT 使用子目录项目来 配置多个子工程 子模块 简述 项目配置概览 项目的多工程配置 使用多模块 特别鸣谢 Qt 之 pro 配置多个子工程 子模块 Qt Creator创建子目录项目并自定义目标文件输出目录 使用子目录项目来 配置多个子工
  • C语言入门——适合练手的密码本项目

    一 引言 学C语言有一段时间了 趁着正好做了密码本的小项目 把它分享出来 二 思路与原理 密码本 见名知意 就是存放账号密码 起到备忘录作用的本子 将需要备忘的数据通过加密存放在文本文件中 打开的文本文件为加密文本 需要通过软件查看已经存放
  • 关于Redis的事件回调解析以及docker中的配置

    基本概念 Redis的过期回调可以实现我们的redsi的key在过期的时候回调一些接口从而来实现项目中需要的一些功能 比如我们想在订单超时的时候进行关闭 可以用这个来进行一个简单的实现 当然实际的项目中能否这样使用我们暂且不做讨论 这里只是

随机推荐

  • AIGC将颠覆设计界?!今晚直播间解密AIGC之图像生成史

    从DeepFake 风格迁移到 Midjourney DALL E AIGC的应用一次又一次带给我们惊喜 这些背后的蕴藏着哪些原理 赶快加入AIGC图像生成直播课 探索AI生成艺术的奥秘 2月28日 3月7日每周二晚8点 系列直播课 扫码报
  • c++如何创建项目

    C 是一门广泛应用于计算机科学领域的编程语言 它能够实现高效的程序编写和性能优化 在开始C 编程之前 我们需要创建一个新的项目来存储我们的代码和资源文件 本文将详细介绍如何在各个平台上使用不同的IDE 集成开发环境 创建C 项目 1 在Wi
  • C#中关于InvokeRequired 属性 与Invoke方法

    C 中禁止跨线程直接访问控件 InvokeRequired是为了解决这个问题而产生的 当一个控件的InvokeRequired属性值为真时 说明有一个创建它以外的线程想访问它 Windows 窗体中的控件被绑定到特定的线程 不具备线程安全性
  • linux中shell脚本手动可执行,定时任务却失败

    linux中shell脚本手动执行没问题 crontab定时执行失败 可能是环境配置出问题 原本代码为 bin sh cd root goItem test go run main go 可在 bin sh 后加入 source etc p
  • HTML select下拉菜单选中选项后直接触发函数

    可以通过onchange事件实现
  • ArcGIS For Android 在地图上显示属性图形信息和属性文本信息

    前言 本文使用的是10 2 8的版本 需求是要在切片地图上显示出自定义的村镇界线 森林地块的树种信息等信息 方法一 第一种就是利用Symbol类中的TextSymbol来显示 使用的是 shp文件 TextSymbol textSymbol
  • 常见挖矿病毒处理方法(qW3xT/Ddgs.3011/S01wipefs/acpidtd/MSFC)

    常见挖矿病毒处理方法 1 常见病毒 病毒名称 qW3xT 现象 占用超高CPU 进程查杀之后自启动 中毒案例 2 病毒名称 Ddgs 3011 现象 占用超高CPU 进程查杀之后自启动 中毒案例 3 病毒名称 S01wipefs 现象 占用
  • zookeerp安装与配置

    1 zookeeper官网 https zookeeper apache org 2 找到download 然后打开的页面打开archive 版本页面不选择内测或者公测版本 选择一个稳定的 然后下载下来 解压 进入红框目录 在红框目录打cm
  • [1211]python imagehash库简单运用

    文章目录 python imagehash库简单运用 基本原理 什么是哈希 hash 什么是图像哈希 imagehash 安装 基本用法 imagehash中的四种图像哈希方式 phash ahash dhash 小波hash percep
  • RIP实验(详细步骤)

    一 设置每个路由器的环回地址和IP地址 二 设置完IP后 输入RIP 再输入该路由器的环回和所在网段 只是自己本身有的 而不是宣告学习到的 以此类推 宣告完之后再给每一个端口设置密文认证 如上图所示 但是路由器四环回不用宣告 3 缺省路由
  • 2023智源大会议程公开丨基础模型前沿技术论坛

    6月9日 2023北京智源大会 将邀请这一领域的探索者 实践者 以及关心智能科学的每个人 共同拉开未来舞台的帷幕 你准备好了吗 与会知名嘉宾包括 图灵奖得主Yann LeCun 图灵奖得主Geoffrey Hinton OpenAI创始人S
  • 剑指 Offer 55 - I. 二叉树的深度(java+python)

    输入一棵二叉树的根节点 求该树的深度 从根节点到叶节点依次经过的节点 含根 叶节点 形成树的一条路径 最长路径的长度为树的深度 例如 给定二叉树 3 9 20 null null 15 7 3 9 20 15 7 返回它的最大深度 3 提示
  • 为什么WebSocket连接可以实现全双工通信而HTTP连接不行呢?WebSocket协议详解

    WebSocket WebSocket是HTML5新增的协议 它的目的是在浏览器和服务器之间建立一个不受限的双向通信的通道 比如说 服务器可以在任意时刻发送消息给浏览器 为什么传统的HTTP协议不能做到WebSocket实现的功能 这是因为
  • 微信小程序用户隐私保护指引设置怎么填?

    我们在微信小程序审核时 可能会出现下图的提示 需要我们完善用户隐私协议 此时点击上图中的 了解详情 进入下图的界面 点击下图所示选项 点击 确认以上内容 勾选以上两项 再确认 再对照上图填写 确认生成协议 就可以提交小程序审核了
  • java 泛型 动态,如何动态地指定Java泛型类

    If I specific a method which return a generic class how can I do than I can specific the type of generic class dynamicly
  • Python 实现斐波那契数列中的前50个

    斐波那契数列 Fibonacci sequence 又称黄金分割数列 因数学家列昂纳多 斐波那契 Leonardoda Fibonacci 以兔子繁殖为例子而引入 故又称为 兔子数列 指的是这样一个数列 1 1 2 3 5 8 13 21
  • Redis 之 list数据类型

    基本操作 lpush 从左端插入元素 可以一次插入多个 rpush 从右端插入元素 可以一次插入多个 lpop 左侧取出一个元素 取出后list元素个数减1 rpop 从右端取出一个元素 取出后list元素个数减1 llen 查看list的
  • Java爬虫:用java爬取小说

    Java也能做爬虫 现在提到爬虫人第一个想到的就是python 其实使用Java编写爬虫也是很好的选择 下面给大家展示一个使用Java基础语言编写的爬取小说的案例 实现功能 爬取目标网站全本小说 代码编写环境 JDK 1 8 0 191 E
  • 拓世大模型引领传统能源大变革,开启煤矿产业升级新范式

    引言 煤炭 因其丰富储量和广泛用途 被誉为工业食粮 自第一次工业革命以来一直是人类生产生活中不可或缺的能源材料 我国是世界煤炭资源储存大国 据国家统计局数据 2022年我国煤炭产量达到45 6亿吨 同比增长10 5 作为世界第二大经济体 我
  • HTTP服务器(三)

    下面实现处理动态页面的逻辑 创建一对命名管道 fork创建子进程 让父子进程执行不同的任务 值得注意的是 由于管道数据流动是单向的 所以要创建一对 父进程将必要的信息通过管道传递给子进程 子进程将计算的结果通过管道传递给父进程 int Ha