TinyHttpd源码精读(三)

在上一章中我们一起看了如何实现静态的网页,在这里我们一起看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服务感兴趣的也能自己手动开始由简入难慢慢丰富自己的功能。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

3、SLAM算法中的运动模型和观测模型和常用传感器类型

SLAM算法中的运动模型和观测模型 常用传感器类型&#xff1a;局部传感器&#xff08;相机、IMU、激光雷达等&#xff09;在小区域内提供了精确的位姿&#xff0c;而全局传感器&#xff08;GPS、磁力计、气压计等&#xff09;在大尺度环境中提供了有噪声但是全局无漂移的定位。 …

【three.js】光源对物体表面影响

目录 一、受光照影响材质 二、光源简介 2.1 点光源 光源位置 点光源辅助观察 完整代码,粘贴即用 2.2 环境光 2.3 平行光 平行光辅助观察 实际生活中物体表面的明暗效果是会受到光照的影响,比如晚上不开灯,你就看不到物体,灯光比较暗,物体也比较暗。在threejs中,…

金融数据中心布线运维管理解决方案

金融行业的核心业务&#xff0c;如交易、支付、结算等&#xff0c;对网络的依赖程度极高。布线作为网络基础设施的重要组成部分&#xff0c;其稳定性和可靠性直接关系到业务的连续运行。因此&#xff0c;良好的布线管理能够确保网络系统的稳定运行&#xff0c;减少因网络故障导…

安装sqlserver2022 express

1、下载 SQL Server 下载 | Microsoft 双击sql2022-ssei-expr 2、安装 下载完成以后&#xff0c;将会出现以下对话框 &#xff1a; 点击【全新SQL Server独立安装或向现有安全添加功能】 下一步&#xff0c;下一步&#xff1a; 下一步&#xff1a; 下一步&#xff0c;这里我…

encoding Token和embedding 傻傻分不清楚?

encoding 编码 “encoding” 是一个在计算机科学和人工智能领域广泛使用的术语&#xff0c;它可以指代多种不同的过程和方法。核心就是编码&#xff1a;用某些数字来表示特定的信息。当然你或许会说字符集(Unicode)更理解这种概念&#xff0c;编码更强调这种动态的过程。而字符…

Rejetto HTTP文件服务器 未授权RCE漏洞复现(CVE-2024-23692)

0x01 产品简介 Rejetto HTTP File Server(HFS)是一个基于HTTP协议的文件服务器软件,旨在为用户提供简单、轻量级且易于使用的文件共享解决方案。功能强大、易于使用的文件服务器软件,无论是个人使用还是团队协作,HFS都能满足用户的需求,提高工作效率。 0x02 漏洞概述 …

vue3根据按钮切换更新echarts对应的数据

效果图 初始化注意 setOption的函数定义&#xff0c;option是指图表的配置项和数据&#xff0c;notMerge是指是否不跟之前设置的 option 进行合并。默认为 false。即表示合并。如果为 true&#xff0c;表示所有组件都会被删除&#xff0c;然后根据新option 创建所有新组件 //…

springboot+vue前后端分离项目中使用jwt实现登录认证

文章目录 一、后端代码1.响应工具类2.jwt工具类3.登录用户实体类4.登录接口5.测试接口6.过滤器7.启动类 二、前端代码1.登录页index 页面 三、效果展示 一、后端代码 1.响应工具类 package com.etime.util;import com.etime.vo.ResponseModel; import com.fasterxml.jackson.…

采用java+springboot+vue+uniapp自主研发的智慧城管源码,城管综合执法平台源代码

智慧城管执法平台源码&#xff0c;PCAPP端全套源码&#xff0c;城管综合执法系统源码。 智慧城管系统拥有自主版权&#xff0c;项目落地案例&#xff0c;有演示&#xff0c;适合二次开发项目使用。 智慧城管执法系统旨在提高城市管理效率&#xff0c;涵盖了城市管理中的很多业务…

Linux kernel本地权限提升漏洞(CentOS8升级内核的解决方案)

一、CentOS8升级kernel内核的必要性 1、增强系统的安全性。 升级CentOS内核可以提供更好的安全性保障。新的内核版本通常包含了的安全补丁和漏洞修复&#xff0c;可以有效防止系统遭受恶意攻击&#xff0c;提高系统的稳定性和安全性。 2、优化硬件兼容性。 CentOS升级内核可以…

深度解析地推效果,Xinstall助您精准提升推广成效

在移动互联网时代&#xff0c;App的推广方式日趋多样化&#xff0c;其中地推作为线下推广的重要一环&#xff0c;因其成本相对较低、互动性强等特点&#xff0c;受到越来越多App厂商的青睐。然而&#xff0c;地推过程中往往面临着数据收集困难、获客率低、业务员费用结算标准难…

HTML5+CSS3小实例:粘性文字的滚动效果

实例:粘性文字的滚动效果 技术栈:HTML+CSS 效果: 源码: 【HTML】 <!DOCTYPE html> <html lang="zh-CN"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-sca…

web刷题记录(5)

[羊城杯 2020]easycon 进来以后就是一个默认测试页面&#xff0c; 在这种默认界面里&#xff0c;我觉得一般不会有什么注入点之类的&#xff0c;所以这里先选择用御剑扫扫目录看看有没有什么存在关键信息的页面 扫了一半发现&#xff0c;很多都是和index.php文件有关&#xff0…

运维系列.在Docker中使用Grafana

运维专题 在Docker中使用Grafana - 文章信息 - Author: 李俊才 (jcLee95) Visit me at CSDN: https://jclee95.blog.csdn.netMy WebSite&#xff1a;http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAddress of this article:https://blog.csdn.net/qq_2855026…

JAVA开发 PDF文件生成表格,表格根据内容自动调整高度

1、展示效果 2、相关功能实现 JAVA开发 使用Apache PDFBox库生成PDF文件&#xff0c;绘制表格 3、实现代码 import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.PDPageContentStream; import org.ap…

龙芯+RT-Thread+LVGL实战笔记(36)——密码锁完善

【写在前面】不知不觉中,又临近学期末了。这个学期,因为一些特殊原因,一直没怎么更新本教程,而且不得已上调了本教程的价格,在此笔者深表歉意。另一方面,自己带的学生发挥不佳,很遗憾未能闯进国赛,为此笔者也郁闷了相当长一段时间。事已至此,也只能慢慢释然,来年再战…

Python实现音乐播放器 -----------内附源码

Python做一个简易的音乐播放器 简易音乐播放器 import time import pygamefile r歌曲路径 pygame.mixer.init() print(正在播放,file) track pygame.mixer.music.load(file) pygame.mixer.music.play() time.sleep(130) pygame.mixer.music.stop()运行效果&#xff1a; 开始…

计算机网络:网络层 - IPv4地址

计算机网络&#xff1a;网络层 - IPv4地址 分类编址划分子网子网掩码 无分类编址 CIDRCIDR 地址块构造超网 在酒店中&#xff0c;每个房间都有门牌号码&#xff0c;服务员送餐时&#xff0c;就可以根据门牌号码来判断一份餐要送到那个房间。 在网络中也是如此&#xff0c;一份…

万万没想到,一个不起眼的小功能,差点把我们项目搞崩溃!

大家好&#xff0c;我是程序员鱼皮。今天分享一个真实项目开发的小故事。 故事 最近我们团队一直在持续更新编程导航网站&#xff0c;优化了界面&#xff0c;也新增了不少功能。现在网站长下面这样&#xff0c;是不是看着比以前舒服多了&#xff1f; 编程导航&#xff1a;htt…

2024泰迪智能科技大数据实训室方案

大数据实训室的主要目的是培养大数据平台运维项目的实践能力,以数据计算、分析、挖掘和可视化的案例训练为辅助。实训室旨在培养德智体全面发展、遵纪守法、掌握大数据平台运维基本技能、具备大数据应用、分析和系统管理与运维能力的高素质大数据技术人才。 大数据实训室建设的…