TinyHttpd源码精读(三)

news2025/1/16 17:29:08

在上一章中我们一起看了如何实现静态的网页,在这里我们一起看Tinyhttpd最后的一部分,动态网页的实现:在这里首先声明下因为cgi脚本的支持问题,所以我会新建一个简单的cgi脚本然后将路径导向到这个脚本:

0.perl的配置:

sudo apt update
sudo apt install build-essential libssl-dev zlib1g-dev
sudo apt install perl

1.新增cgi脚本内容:

        在color.cgi同级目录下新增一个temp.cgi的文件,然后内容如下:

#!/usr/bin/perl
use strict;
use warnings;

print "Content-Type: text/html\n\n";
print "<html>\n";
print "<head><title>Simple CGI Script</title></head>\n";
print "<body>\n";
print "<h1>Hello, World!</h1>\n";
print "</body>\n";
print "</html>\n";

  2.修改响应路径:

        在index.html中将<FORM ACTION="color.cgi" METHOD="POST">替换成:

        <FORM ACTION="temp.cgi" METHOD="POST">

3.运行httpd

        然后再对话框内随便输入,点击submit即可看到替换后的效果:

        

4.execute_cgi函数:

        这段代码是带有注释的execute_cgi函数,已经在实现cgi的重要逻辑中都加上了log。诸位可以自行选择直接看还是先看后面的简单解析。

void execute_cgi(int client, const char *path,
        const char *method, const char *query_string)
{
    char buf[1024];
    int cgi_output[2];
    int cgi_input[2];
    pid_t pid;
    int status;
    int i;
    char c;
    int numchars = 1;
    int content_length = -1;
    //确认请求方法
    buf[0] = 'A'; buf[1] = '\0';
    if (strcasecmp(method, "GET") == 0)
        while ((numchars > 0) && strcmp("\n", buf))  /* read & discard headers */
            numchars = get_line(client, buf, sizeof(buf));
    else if (strcasecmp(method, "POST") == 0) /*POST*/
    {
        numchars = get_line(client, buf, sizeof(buf));
        while ((numchars > 0) && strcmp("\n", buf))
        {
            buf[15] = '\0';
            if (strcasecmp(buf, "Content-Length:") == 0)
                content_length = atoi(&(buf[16]));
            numchars = get_line(client, buf, sizeof(buf));
        }
        if (content_length == -1) {
            bad_request(client);
            return;
        }
    }
    else/*HEAD or other*/
    {
    }

    //pipe是创建一个匿名的双向管道。允许数据在父子进程或者相关联进程之前单向流动
    //cgi_output一般是一个整形数组,用来存放管道的两个文件描述符。如果调用成功,cgi_output[0]会存放管道的读段描述符,cgi_output[1]会存放管道的写段描述符
    //如果返回值小于0则表示pipe调用失败.
    if (pipe(cgi_output) < 0) {
        cannot_execute(client);
        return;
    }
    if (pipe(cgi_input) < 0) {
        cannot_execute(client);
        return;
    }
    //fork用于创建一个与调用进程几乎完全相同的子进程,如果调用成功,则返回子进程的进程ID,否则返回-1.
    if ( (pid = fork()) < 0 ) {
        cannot_execute(client);
        return;
    }
    sprintf(buf, "HTTP/1.0 200 OK\r\n");
    send(client, buf, strlen(buf), 0);
    //如果当前在子进程中则pid为0
    if (pid == 0)  /* child: CGI script */
    {
        char meth_env[255];
        char query_env[255];
        char length_env[255];

        //dup2的作用是复制文件描述符。在这里他将将cgi_output[1]复制到标准输出,将cgi_input[0]复制到标准输入。
        //这意味着任何原本要输出到终端的输出现在都会重定向到管道中。这样就能在父子进程直接进行数据传递了
        dup2(cgi_output[1], STDOUT);
        dup2(cgi_input[0], STDIN);

        close(cgi_output[0]);
        close(cgi_input[1]);
        sprintf(meth_env, "REQUEST_METHOD=%s", method);
        putenv(meth_env);
        if (strcasecmp(method, "GET") == 0) {
            sprintf(query_env, "QUERY_STRING=%s", query_string);
            putenv(query_env);
        }
        else {   /* POST */
            sprintf(length_env, "CONTENT_LENGTH=%d", content_length);
            putenv(length_env);
        }
        //根据path执行脚本
        execl(path, NULL);
        exit(0);
    } else {    /* parent */
        //在父进程显示cgi脚本
        close(cgi_output[1]);
        close(cgi_input[0]);
        //在post的情况下根据读取的客户端的输出将内容传递到子管道中
        if (strcasecmp(method, "POST") == 0)
            for (i = 0; i < content_length; i++) {
                recv(client, &c, 1, 0);
                write(cgi_input[1], &c, 1);
            }
        //将子进程的输出传递到客户端
        while (read(cgi_output[0], &c, 1) > 0)
            send(client, &c, 1, 0);

        close(cgi_output[0]);
        close(cgi_input[1]);
        waitpid(pid, &status, 0);
    }
}

5.execute_cgi函数简单解析:

        主体的逻辑就是从pipe函数那里开始,创建一个子进程,父子进程的环境啥的都完全一样,然后再子进程里面打开cgi脚本,并且将脚本的输出通过dup2函数和cgi_output,cgi_input传递到父进程里面,然后由父进程传递到client(网页)中。

6.总结:

        从精读1,2,3我们基本搞清楚了TinyHttpd这个项目的基本运行逻辑,以及静态网页动态网页显示的思路和逻辑。当然后面的cgi这个算是一个精简版讲解,受限于cgi的布置,我们也不太容易一睹原项目中cgi的风采,但是思路是一样的。其中对于异常情况的处理和思路也是值得我们去学习的,不过我并不是主修web服务这块的,所以目前这块我的理解不够深入,暂时也不打算这样深入。后面我将根据我阅读的TinyHttpd的心得,自己写一个简易版本的内容出来。各位也可以自己动手试试,相信各位自己动手写完后肯定是受益匪浅,收获满满。对于socket的理解和使用的逻辑也会更上一层楼,对于C++web服务感兴趣的也能自己手动开始由简入难慢慢丰富自己的功能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1812715.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2024年建筑、水利交通与工程管理国际学术会议(ICAWRTEM 2024)

全称&#xff1a;2024年建筑、水利交通与工程管理国际学术会议&#xff08;ICAWRTEM 2024&#xff09; 会议网址:http://www.icawrtem.com会议地点: 广州投稿邮箱&#xff1a;icawrtemsub-conf.com 投稿标题&#xff1a;ICAWRTEM 2024ArticleTEL。投稿时请在邮件正文备注&#…

MySQL之高级特性(一)

高级特性 外键约束 InnoDB是目前MySQL中唯一支持外键的内置存储引擎&#xff0c;所以如果需要外键支持那选择就不多了。使用外键是有成本的。比如外键通常都要求每次在修改数据时都要在另一张表中多执行一次查找操作。虽然InnoDB强制外键使用索引&#xff0c;但还是无法消除这…

一夜之间,苹果杀死无数AI工具创业公司!GPT-4o深度整合进苹果

就在刚刚&#xff0c;苹果发布会WWDC2024官宣了一系列AI相关的重磅升级。 由于这一波AI升级攒的太大了&#xff0c;苹果甚至索性创造了一个新的概念——苹果智能&#xff08;Apple Intelligence&#xff09;。 如果你认为 苹果智能 Siri升级&#xff0c;那你就大错特错了。 …

分层解耦

三层架构 controller:控制层&#xff0c;接收前端发送的请求&#xff0c;对请求进行处理&#xff0c;并响应数据&#xff0c; service:业务逻辑层&#xff0c;处理具体的业务逻辑。 dao:数据访问层(Data Access Object)(持久层)&#xff0c;负责数据访问操作&#xff0c;包括数…

动态规划(多重背包问题+二进制优化)

引言 多重背包&#xff0c;相对于01背包来说&#xff0c;多重背包是每个物品会有相应的个数&#xff0c;最多可以选那么多个&#xff0c;因而对于朴素多重背包&#xff0c;需要在01背包的基础上&#xff0c;再加一层物品的循环 朴素多重背包例题 P2347 [NOIP1996 提高组] 砝…

【Affine / Perspective Transformation】

文章目录 仿射变换介绍仿射变换 python 实现——cv2.warpAffine透视变换透视变换 python 实现——cv2.warpPerspective牛刀小试各类变换的区别与联系仿射变换和单应性矩阵透视变换和单应性矩阵 仿射变换介绍 仿射变换&#xff08;Affine Transformation&#xff09;&#xff0…

【话题】评价GPT-4o:从革命性技术到未来挑战

大家好&#xff0c;我是全栈小5&#xff0c;欢迎阅读小5的系列文章&#xff0c;这是《话题》系列文章 目录 引言技术原理应用领域实际案例优势挑战局限性未来展望文章推荐 引言 在人工智能领域&#xff0c;自然语言处理&#xff08;NLP&#xff09;技术的进步一直是推动技术革…

odoo15升级odoo16遇到的问题及解决过程

odoo15升级odoo16遇到的问题 PyMuPDF 档案管理整理时,从15升级16出现如下错误: File "f:\od162306\dms\dmssp\models\shenqb.py", line 136, in doc_fj_pdf doc.SaveAs(ftem, FileFormat=17) # input_file.replace(".docx", ".pdf") F…

鸿蒙开发文件管理:【@ohos.environment (目录环境能力)】

目录环境能力 该模块提供环境目录能力&#xff0c;获取内存存储根目录、公共文件根目录的JS接口。 说明&#xff1a; 本模块首批接口从API version 8开始支持。后续版本的新增接口&#xff0c;采用上角标单独标记接口的起始版本。本模块接口为系统接口&#xff0c;三方应用不支…

Pythone 程序打包成 exe

1.安装pyinstaller # 安装 pip install pyinstaller # 查看版本 pyinstaller -v2.更新pyinstaller 版本 # 更新 pip install --upgrade pyinstaller # 查看版本 pyinstaller -v3.切换到 py文件所在目录 #切换到.py所在的目录 E: cd cd E:\x-svn_x-local\04PythoneProjects\A…

滴滴出行 大数据研发实习生【继任】

大数据研发实习生JD 职位描述 1、负责滴滴核心业务的数据建设&#xff0c;设计并打造适应滴滴一站式出行平台业务特点的数仓体系。 2、负责抽象核心业务流程&#xff0c;沉淀业务通用分析框架&#xff0c;开发数仓中间层和数据应用产品。 3、负责不断完善数据治理体系&#xff…

远程链接服务 ssh

① 指定用户身份登录 ssh root10.36.105.100 ssh jim10.36.105.100 ② 不登陆远程执行命令 ssh root10.36.105.100 ls /opt ③ 远程拷贝 scp -r // 拷贝目录 -p // 指定端口 将本地文件拷贝给远程主机 scp -r /opt/test1 10.36.105.100:/tmp/// 将本…

使用 ML.NET CLI 自动进行模型训练

ML.NET CLI 可为 .NET 开发人员自动生成模型。 若要单独使用 ML.NET API(不使用 ML.NET AutoML CLI),需要选择训练程序(针对特定任务的机器学习算法的实现),以及要应用到数据的数据转换集(特征工程)。 每个数据集的最佳管道各不相同,从所有选择中选择最佳算法增加了复…

轻兔推荐 —— NeatDownloadManager

via&#xff1a;轻兔推荐 - https://app.lighttools.net/ 简介 NeatDownloadManager简称NDM&#xff0c;跟IDM同样出名的网络下载器&#xff0c;安装对应的浏览器器扩展后&#xff0c;可接管浏览器下载 - 软件体积非常小&#xff0c;Windows版900KB&#xff0c;很难想象当今的…

UE5 渲染性能优化 学习笔记

主要考虑三个点&#xff1a; 1、灯光 2、半透明物体 3、后处理 1、Game&#xff1a;CPU对游戏代码的处理工作 2、Draw&#xff1a;CPU为GPU准备数据所做的工作 3、GPU Time&#xff1a;就是GPU所渲染需要花的时间 UE5的命令行指令 里面说明了某个指令有什么用处 以及启动…

隐私计算(1)数据可信流通

目录 1. 数据可信流通体系 2. 信任的基石 3.数据流通中的不可信风险 可信链条的级联失效&#xff0c;以至于崩塌 4.数据内循环与外循环&#xff1a;传统数据安全的信任基础 4.1内循环 4.2外循环 5. 技术信任 6. 密态计算 7.技术信任 7.1可信数字身份 7.2 使用权跨域…

【大数据·hadoop】项目实践:IDEA实现WordCount词频统计项目

一、环境准备 1.1&#xff1a;在ubuntu上安装idea 我们知道&#xff0c;在hdfs分布式系统中&#xff0c;MapReduce这部分程序是需要用户自己开发&#xff0c;我们在ubuntu上安装idea也是为了开发wordcount所需的Map和Reduce程序&#xff0c;最后打包&#xff0c;上传到hdfs上…

贷款业务——LPR、APR、IRR

文章目录 LPR&#xff08;Loan Prime Rate&#xff09;贷款市场报价利率APR&#xff08;Annual Percentage Rate&#xff09;年化百分比利率IRR&#xff08;Internal Rate of Return&#xff09;内部收益率 LPR、APR 和 IRR 是三个不同的金融术语&#xff0c;LPR 是一种市场利率…

Catia装配体零件复制

先选中要复制的零件 然后选中复制到的父节点才可以。 否则 另外一种方法是多实例化

【C++】继承|切片|菱形继承|虚继承

目录 ​编辑 一.什么是继承 三大特性 继承的语法 访问控制 继承的总结 二.继承的作用域 三.切片 四. 派生类的默认成员函数 构造函数 析构函数 拷贝构造 赋值运算符重载 五.单继承和多继承 单继承 多继承 菱形继承 解决方式 六.虚继承 一.什么是继承 C中的…