【C/C++】web服务器项目开发总结【请求 | 响应 | CGI】

news2024/11/5 21:45:38

  博客主页:花果山~程序猿-CSDN博客

文章分栏:Linux_花果山~程序猿的博客-CSDN博客

关注我一起学习,一起进步,一起探索编程的无限可能吧!让我们一起努力,一起成长!

在这里插入图片描述

目录

一,背景

二,目标

三,基本描述

四,技术特点

网络基本认识补充

web服务器(http服务器工作原理)

http 1.0与http 1.1

区分URI & URL & URN

五,技术要点 

1. http请求&响应

2. 请求方法

3.http响应报文状态码设置

4.CGI机制

CGI实现原理

5.线程池优化


嗨!收到一张超美的图,愿你每天都能顺心!

一,背景

http 协议被广泛使用,从移动端, pc 端浏览器, http 协议无疑是打开互联网应用窗口的重要协议, http 在网络应用层中的地位不可撼动,是能准确区分前后台的重要协议。

二,目标

http 协议的理论学习,从零开始完成 web 服务器开发,坐拥下三层协议,从技术到应用。

三,基本描述

        采用C/S 模型,编写支持中小型应用的 http ,并结合 mysql ,理解常见互联网应用行为,做完该项目,你可以从技术上完全理解从你上网开始,到关闭浏览器的所有操作中的技术细节。

四,技术特点

  • 网络编程(TCP/IP协议, socket流式套接字,http协议)
  • 多线程技术
  • cgi技术
  • shell脚本
  • 线程池

项目定位:研发岗

开发环境:centos7 + vim/g++/vscode + c/c++

网络基本认识补充

web服务器(http服务器工作原理)

http 1.0与http 1.1

目前主流的浏览器使用http1.1

http1.0优点:

  • 简单快速,HTTP服务器的程序规模小,因而通信速度很快。
  • 灵活,HTTP允许传输任意类型的数据对象,正在传输的类型由Content-Type加以标记。
  • 无连接,每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。(http/1.0具有的功能,http/1.1兼容)
http 协议每当有新的请求产生,就会有对应的新响应产生。协议本身并不会保留你之前的一切请求或者响应,这是为了更快的处理大量的事务,确保协议的可伸缩性。

http1.1的优化:可是,随着web的发展,因为无状态而导致业务处理变的棘手起来。比如保持用户的登陆状态(由于无状态,所以每次访问不知道用户信息,而又不可能让用户每次登录)

http/1.1 虽然也是无状态的协议,但是为了保持状态的功能,引入了 cookie 技术

区分URI & URL & URN

URI, uniform resource identifier ,统一资源标识符,用来唯一的标识一个资源
URL, uniform resource locator ,统一资源定位符,它是一种具体的 URI ,即 URL 可以用来标识一个资源,而且还指明了如何locate 这个资源。
URN,uniform resource name ,统一资源命名,是通过名字来标识资源,比如 mailto:javanet@java.sun.com

例如:

URI: /home/index.html
URL: www.xxx.com:/home/index.html

五,技术要点 

1. http请求&响应

下面是对应的示意图

请求详细的:

响应详细的: 

在此项目中对请求,响应报文头进行简化,代表大致即可,主要是首行和正文

测试工具:telnet(linux),postman(windows)

2. 请求方法

GET(多服务器请求资源):

  • GET 请求中的参数会被附加在 URL 后面,因此可以被浏览器缓存,并且可以在浏览历史中看到,也可能被记录在网络日志中。这使得 GET 请求不适合传输敏感信息。
  • 有浏览器URL长度限制;
  • 安全性较差;

POST(多向服务器上传数据):

  • POST 请求的数据不会显示在 URL 中,也不会被缓存或保存在历史记录中,因此相对更安全。
  • 数据在正文,大小没有URL限制;
  • 正文信息,不会被URL记录,安全性较高;

等等其他请求方法用的少,感兴趣可以查查

3.http响应报文状态码设置

HTTP 状态码( HTTP Status Code )是用以表示服务器 HTTP 响应状态的 3 位数字代码客户端(浏览器)通过状态码,就可以知道服务
器端是否正确的处理的请求,如果不正确,是因为什么原因导致的( 404

如:

200  OK

404  资源未找到

具体状态码详细可以查看详细资料

4.CGI机制

        CGI(Common Gateway Interface) 是 WWW 技术中最重要的技术之一,有着不可替代的重要地位。 CGI 是外部应用程序(CGI 程序)与 WEB 服务器之间的接口标准,是在 CGI 程序和 Web 服务器之间传递信息的过程。
        浏览器除了从服务器下获得资源(网页,图片,文字等),有时候还有能上传一些东西(提交表单,注册用户之类的),看看我们目前的http只能进行获得资源,并不能够进行上传资源,所以目前 http 并不具有交互式
为了让我们的网站能够实现交互式,我们需要使用CGI完成,时刻记着,我们目前是要写一个 http ,所以, CGI 的所有交互细节,都需要我们来完成。
理论上,可以使用任何语言来编写CGI 程序(如:java,php等以及脚本语言)。
实现原理图

CGI实现原理

我们知道带参数的GET和POST是携带数据的,处理数据是需要程序运行才能得到结果,server线程中执行程序的就有 execl程序替换法,将子进程替换为能处理数据的程序,
但execl是进程替换,server线程替换则会替换整个server进程,所以需要server线程fork出的子进程进行替换即可。
接下来,需要进程通信,传递从请求中获取的参数,我们可以通过匿名管道法(接口:pipe)
我们知道进程替换会保留原有的 文件描述符表,环境变量,信号处理程序(保留旧进程的信号处理方式)等
子进程创建好后,那子进程如何获取参数?
(1)环境变量传递
适合条件:参数量小,如带参的GET方法
接口:  putenvgetenv来设置,读取环境变量
(2)进程间通信
适合条件:参数量大,如POST方法

 而进行程序替换后,我们并不知道具体的管道描述符,因此在替换前,需要将pipe的输入输出重定向给标准输入输出,这样子进程只需要使用cout(1),cin(0)即可与向父进程(server线程)进行进程间通信,传递参数&结果。

期间也需要通过环境变量告知子进程参数大小

CGI代码如下:

int ProcessCGI()
    {
        std::string tmp_iurlb = ".";
        tmp_iurlb += address;
        int output[2]; // 线程发数据
        int inget[2]; // 线程接收结果
        pipe(output);
        pipe(inget);
        pid_t pd = fork();
        // 线程为主视角
        if (pd == 0)
        {
            // 子
            close(output[1]);
            close(inget[0]);
            // 1.接收数据,准备程序替换

            std::string room = "METHOD=";   //请求类型环境变量
            room += method;
            putenv((char *)room.c_str());

            std::string tmp;          // get参数 环境变量
            std::string room_length;  // post正文的长度环境变量

            if (method == "POST")
            {
                room_length = "CONTENT-LENHTH=";
                room_length += std::to_string(content_length);
                putenv((char *)room_length.c_str());
            }
            else if (method == "GET" && parameter.size() != 0)
            {
                tmp = "PARAMENTER=";
                tmp += parameter;
                putenv((char *)tmp.c_str());
            }
            // std::cerr << "debug : excel:" << address.c_str() <<  std::endl;
           
            // 约定:子进程只需从标准输入输出进行获取数据
            dup2(output[0], 0);
            dup2(inget[1], 1);

            execl(("." + address).c_str(), nullptr); // 疑问:既然通过环境变量来传参数,那buff到时候传过去的就是
            close(0);
            close(1);
            std::cerr << "GET EXECL FAIL:" << std::endl;
            return -1;
        }
        else if (pd > 0)
        {
            // 父
            close(output[0]);
            close(inget[1]);

            if (method == "POST");
            {
                const char* str = request_body.c_str();
                int total = 0;
                int size = 0;                
                while ((total <= content_length) && 
                 (size = write(output[1], str + total, request_body.size() - total) > 0))
                 {
                    total += size;
                 }
            }
            
            //接收CGI 返回值
            while (1)
            {
                 char x = 'g';
                 int set =  read(inget[0], &x, 1);
                 if ( x == '\n')
                    break;
                httpresponse.Respone_body.push_back(x);
            }
            // std::cout << "res CGI:" << httpresponse.Respone_body << std::endl;
            int status = 0;
            waitpid(pd, &status, 0); // 线程阻塞试等待
            if (WIFEXITED(status) == 0)
                Logmessage(WARN, "CGI exit with error code");

            close(output[1]);
            close(inget[0]);
            
            return 0;
        }

5.线程池优化

优化如下:
  • 大量链接过来导致服务器内部进程或者线程暴增,进而导致服务器效率严重降低或者挂掉
  • 节省链接请求到来时,创建线程的时间成本
  • 让服务器的效率在一个恒定的稳定区间内(线程个数不增多,CPU调度成本不变)

本项目采用曾经线程池博客进行简单修改,参考博客:

线程池小项目【Linux & C/C++】(踩坑分享)_c++linux项目-CSDN博客

下面用一张示意图梳理一下流程: 

线程池的方法支持中,小型程序,如需支持大程序并发,需要使用epoll,以及一些在外部通过文本控制参数。
六,项目扩展
        
1),技术扩展
  • 实现支持http1.1,长连接,以及处理链接管理,黏包问题
  • 支持更高并发的epoll
  • 添加redis,mysql等
  • 实现为该请求转发器(代理服务)
  • 尝试打包成组件,实现http快速搭建
后续会结合其他项目来扩展。
2),应用扩展
  • 个人简历
  • 个人博客等等

项目代码

Linux: 从0到1 - Gitee.com

结语

   本小节就到这里了,感谢小伙伴的浏览,如果有什么建议,欢迎在评论区评论,如果给小伙伴带来一些收获,请动动你发财的小手点个免费的赞,你的点赞和关注永远是博主创作的动力源泉。

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

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

相关文章

机器学习(西瓜书)第 4 章 决策树

4.1 决策树基本流程 决策树模型 基本流程 在第⑵种情形下&#xff0c;我们把当前结点标记为叶结点&#xff0c;并将其类别设定为该结点所含样本最多的类别&#xff1b;在第⑶种情形下&#xff0c;同样把当前结点标记为叶结点&#xff0c;但将其类别设定为其父结点所含样本最多…

VMware时提示系统尚未修改安装失败

安装VMware安装失败&#xff0c;提示系统尚未修改 有以下解决方案&#xff1a; 1.操作系统不兼容 2.安装文件损坏 3.安装程序错误 4.硬件问题 解决&#xff1a;由于重装系统前&#xff0c;安装过VAware&#xff0c;所以应该操作系统&#xff0c;硬件没有问题。下载一个软件v…

多线程篇(阻塞队列- ArrayBlockingQueue)(持续更新迭代)

目录 一、源码分析 1. 先看个关系图 2. 构造方法 3. 核心属性 4. 核心功能 入队&#xff08;放入数据&#xff09; 出队&#xff08;取出数据&#xff09; 5. 总结 一、源码分析 1. 先看个关系图 PS&#xff1a;先看个关系图 ArrayBlockingQueue是最典型的有界阻塞队…

CSDN文章无水印转成PDF

文章目录 一、打开检查二、点击进入控制台三、在控制台中输入代码 一、打开检查 f11或者右键打开检查 二、点击进入控制台 三、在控制台中输入代码 (function(){ use strict;var articleBox $("div.article_content");articleBox.removeAttr("style&quo…

sping boot 基于 RESTful 风格,模拟增删改查操作

RESTful -> 增&#xff1a;post 删&#xff1a;delete 改: put 查: get RESTful 资源路径&#xff0c;一般以 s 复数结尾 以下是代码示例&#xff1a; package com.example.springboot.controller;import org.springframework.web.bind.annotation.*;RestControll…

EmguCV学习笔记 C# 9.3 移动检测类

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请在显著位置标明本文出处以及作者网名&#xff0c;未经作者允许不得用于商业目的。 EmguCV是一个基于OpenCV的开源免费的跨平台计算机视觉库,它向C#和VB.NET开发者提供了OpenCV库的大部分功能。 教程VB.net版本请访问…

汽车网络安全的未来:将车辆视为端点

汽车行业面临着许多与其他行业的成功企业相同的网络安全风险和威胁&#xff0c;但它也在应对一些独特的风险和威胁。 Nuspire 的首席威胁分析师 Josh Smith&#xff08;一家在汽车领域有着深厚根基并保护通用汽车和斯巴鲁等客户的托管安全服务提供商&#xff09;谈到了当前的风…

【AcWing】852. spfa判断负环

#include<iostream> #include<algorithm> #include<cstring> #include<queue> using namespace std;const int N 1e510;int n,m; int h[N],w[N],e[N],ne[N],idx; int dist[N],cnt[N];//cnt存最短路径的边数 bool st[N];void add(int a,int b,int c){e[…

一文讲懂扩散模型

一文讲懂扩散模型 扩散模型&#xff08;Diffusion Models, DM&#xff09;是近年来在计算机视觉、自然语言处理等领域取得显著进展的一种生成模型。其思想根源可以追溯到非平衡热力学&#xff0c;通过模拟数据的扩散和去噪过程来生成新的样本。以下将详细阐述扩散模型的基本原理…

发动机制造5G智能工厂工业物联数字孪生平台,推进制造业数字化转型

发动机制造作为高端制造业的核心领域之一&#xff0c;正积极探索并引领这一变革。其中&#xff0c;发动机制造5G智能工厂物联数字孪生平台的兴起&#xff0c;不仅为发动机制造业注入了新的活力&#xff0c;也为整个制造业的数字化转型树立了新的标杆。发动机制造5G智能工厂物联…

Linux Centos 7网络配置

本步骤基于Centos 7&#xff0c;使用的虚拟机是VMware Workstation Pro&#xff0c;最终可实现虚拟机与外网互通。如为其他发行版本的linux&#xff0c;可能会有差异。 1、检查外网访问状态 ping www.baidu.com 2、查看网卡配置信息 ip addr 3、配置网卡 cd /etc/sysconfig…

致远个性化之--发起流程页面,去掉【查看流程】按钮

需求 近期在做的项目中&#xff0c;遇到一个需求&#xff0c;想把发起流程页面中的【查看流程】按钮去掉&#xff0c;只让员工预测流程&#xff0c;知道自己的事项流程走向&#xff0c;不让看全局流程图。包含PC端和移动端&#xff0c;以及微协同端。 如下图效果示例&#xff1…

SVN下载安装使用方法

目录 &#x1f315;SVN是什么&#xff1f;&#x1f319;SVN跟Git比的优势&#x1f319;SVN的用处 &#x1f315;下载安装使用方法 &#x1f315;&#x1f319;⭐ &#x1f315;SVN是什么&#xff1f; 代码版本管理工具 它能记住你每次的修改 查看所有的修改记录 恢复到任何历…

如何读.Net Framework 的源码?

.Net Framework的源码可以从这里下载 Download 也可以在线直接浏览 https://referencesource.microsoft.com 这里我们以System.IO.Directory.CreateDirectory函数为例&#xff0c;来说明如何去读.Net Framework的源码。 在ReferenceSource在线界面的搜索框里输入Directory.Cr…

C语言深度剖析--不定期更新的第四弹

哈哈哈哈哈哈&#xff0c;今天一天两更&#xff01; void关键字 void关键字不能用来定义变量&#xff0c;原因是void本身就被编译器解释为空类型&#xff0c;编译器强制地不允许定义变量 定义变量的本质是&#xff1a;开辟空间 而void 作为空类型&#xff0c;理论上不应该开…

NLP自然语言处理学习过程中知识点总结

OOV是什么 OOV 是 “Out Of Vocabulary”的缩写&#xff0c;意思是 “超出词汇表” 或 “未登录词汇”。 在自然语言处理 (NLP) 中&#xff0c;OOV 指的是模型训练时没有见过的词语或词汇。通常&#xff0c;语言模型会为其训练数据中未出现的词汇分配一个特殊的标记。OOV 词汇…

【国赛急救包】数模国赛查重规则及降重技巧

国赛已经快接近尾声了&#xff0c;各位宝宝论文写得怎么样啦~ 今天为大家分享关于国赛查重的一些规则&#xff0c;以及降重技巧&#xff01;快收藏起来吧~ 1. 国赛查重要求及如何查重 • 数学建模国赛的查重除了知网数据库以外&#xff0c;更重要的是自建库的查重比对&#x…

14.1 为什么说k8s中监控更复杂了

本节重点介绍 : k8s中监控变得复杂了&#xff0c;挑战如下 挑战1: 监控的目标种类多挑战2: 监控的目标数量多挑战3: 对象的变更和扩缩特别频繁挑战4: 监控对象访问权限问题 k8s架构图 k8s中监控变得复杂了&#xff0c;挑战如下 挑战1: 监控的目标种类多 对象举例 podnodese…

【kubernetes】配置管理中心Configmap运用

一&#xff0c;介绍 Configmap&#xff08;简写 cm&#xff09;是k8s中的资源对象&#xff0c;用于保存非机密性的配置的&#xff0c;数据可以用key/value键值对的形式保存&#xff0c;也可通过文件的形式保存。 【局限性】&#xff1a;在ConfigMap不是用来保存大量数据的&am…

Windows下Python和PyCharm的应用(二)__快捷键方式的设定

前言 程序写久了&#xff0c;难免会形成自己的编程习惯。比如对某一套快捷键的使用&#xff0c;已经形成了肌肉记忆。 为了方便快捷键的使用&#xff0c;可以在PyCharm中设置自己喜欢的快捷键。 我比较习惯于微软Visual Studio的快捷键设置。&#xff08;因为早些年VC开发用的…