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

  博客主页:花果山~程序猿-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.xdnf.cn/news/1523642.html

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

相关文章

使用 Milvus 和 Streamlit 搭建多模态产品推荐系统

我们可以使用 Milvus 搭建多模态 RAG 应用&#xff0c;用于产品推荐系统。用户只需简单上传一张图片并输入文字描述&#xff0c;Google 的 MagicLens 多模态 Embedding 模型就会将图像和文本编码成一个多模态向量。然后&#xff0c;使用这个向量从 Milvus 向量数据库中找到最相…

C++设计模式——Template Method模板方法模式

一&#xff0c;模板方法模式的定义 模板方法模式是一种行为型设计模式&#xff0c;它先定义了一个算法的大致框架&#xff0c;然后将算法的具体实现步骤分解到多个子类中。 模板方法模式为算法设计了一个抽象的模板&#xff0c;算法的具体代码细节由子类来实现&#xff0c;从…

【Linux】进程状态(RSDT 阻塞 僵尸 孤儿)

目录 进程状态 进程状态的查看 R和S 运行状态 T/t 暂停状态 kill命令 D &#xff08;disk sleep&#xff09;状态、 Z 状态&#xff08;僵尸状态&#xff09; 孤儿状态 运行状态 阻塞状态 进程状态 一个进程通常有三种状态 ◉ 就绪状态&#xff08;Ready&#xff0…

如何验证谷歌seo服务商的实力真假?

要验证谷歌SEO服务商的实力真假&#xff0c;可以通过几种简单有效的方法。 你可以要求对方通过视频会议或上门服务&#xff0c;展示谷歌官方后台的真实数据。 通过Google Search Console的实时数据&#xff0c;你可以直接看到他们为客户提供的服务效果&#xff0c;这样的数据是…

【加密社】如何根据.dat文件恢复密钥

加密社 看了这篇指南&#xff0c;你将了解助记词和密钥地址&#xff08;qianbao&#xff09;背后的基本原理。 以及&#xff0c;如何找回你的大饼密钥。 Not your key, not your coin 如果你不掌握自己加密货币钱包的私钥&#xff0c;那么你实际上并不能完全控制你的资产 在当今…

【STM32开发笔记】STM32H7S78-DK上的CoreMark移植和优化--兼记STM32上的printf重定向实现及常见问题解决

【STM32开发笔记】STM32H7S78-DK上的CoreMark移植和优化--兼记STM32上的printf重定向实现及常见问题解决 一、CoreMark简介二、创建CubeMX项目2.1 选择MCU2.2 配置CPU时钟2.3 配置串口功能2.4 配置LED引脚2.5 生成CMake项目 三、基础功能支持3.1 支持记录耗时3.2 支持printf输出…

基于FPGA的OV5640摄像头图像采集

1.OV5640简介 OV5640是OV&#xff08;OmniVision&#xff09;公司推出的一款CMOS图像传感器&#xff0c;实际感光阵列为&#xff1a;2592 x 1944&#xff08;即500w像素&#xff09;&#xff0c;该传感器内部集成了图像出炉的电路&#xff0c;包括自动曝光控制&#xff08;AEC…

内网渗透-域环境搭建

构建内网环境 在学习内网渗透测试时,需要构建一个内网环境并搭建攻击主机,通过具体操作理解漏洞的工作原理,从而采取相应的防范措施。 一个完整的内网环境,需要各种应用程序、操作系统和网络设备,可能比较复杂。我们只需要搭建其中的核心部分,也就是Linux服务器和 Windows服务…

复变函数在大模型中的应用

1. 导入 说来惭愧&#xff0c;我研究生时的研究方向是复分析&#xff0c;但毕业近十年来几乎没用到它。 我还记得实习时做自我介绍时&#xff0c;我说我的研究方向是复分析。面试官不太了解&#xff0c;我便解释说&#xff0c;这是关于对 -1 开平方得到的虚数 i 的研究。 在…

【iOS】——分类拓展关联对象

分类 OC的动态特征允许使用类别为现有的类添加新方法并且不需要创建子类&#xff0c;不需要访问原有类的源代码。通过使用类别即可动态为现有的类添加新方法&#xff0c;而且可以将类定义模块化分布到多个相关文件。 分类是 Objective-C 中的一种语言特性&#xff0c;它允许你…

缓解webclient频繁报‘Connection prematurely closed BEFORE response’的问题

现象&#xff1a; 我在Java代码中使用org.springframework.web.reactive.function.client.WebClient进行网络请求&#xff0c;一开始会有比较多的偶发报错&#xff1a;Connection prematurely closed BEFORE response&#xff0c;网络连接莫名其妙就断了。 处理&#xff1a; …

pm2 + linux + nginx

pm2 pm2是一个用于管理node项目的工具 前言 有如下两个文件 index.js const express require("express"); const app express(); const port 9999;app.get("/index", (req, res) > {res.json({code:200,msg:"songzx001"}) });app.lis…

学习硬件测试06:IIC(SHT30)+HMI串口屏+RS485(modbus)+SPI Flash读写+CAN通信(P81、P91、P95、P120、)

文章以下内容全部为硬件相关知识&#xff0c;鲜有软件知识&#xff0c;并且记的是自己需要的部分&#xff0c;大家可能看不明白。 一、IIC&#xff08;SHT30 数字温湿度传感器&#xff09; 1.1实验现象 1、软件模拟 I2C 协议与 SHT30 数字温湿度传感器通讯&#xff1b; &am…

怎么把视频转换成mp4:好用的mp4格式转换器免费版推荐

用手机或者其他拍摄设备记录生活已经成为一种日常&#xff0c;当你想把手机里储存的日常小确幸发布到平台上时&#xff0c;才发现你视频的格式在平台上并不被支持。这个事实难免让人丧气。如果你还想继续上传视频的话&#xff0c;就不得不把视频格式转换成被平台支持的mp4格式。…

ELK系列之一---探索ELK奇妙世界:初识日志界大名鼎鼎的ES集群!

目录 一、为什么要使用ELK 二、ELK简介 三、Elaticsearch入门 3.1、什么是elaticsearch 3.2、elaticsearch的底层优点 3.2.1、全文检索 3.2.2、倒排索引 3.3、elaticsearch集群原理 一、为什么要使用ELK 一般我们需要进行日志分析场景&#xff1a;直接在日志文件中 gre…

Redis从入门到入门(上)

1.Redis概述 文章目录 1.Redis概述1.1 什么是Redis1.2 Redis的应用场景 2.Linux下Redis的安装与使用2.1 Redis下载2.2 Redis的启动2.3 Redis配置2.4 连接Redis 1.1 什么是Redis Redis是用C语言开发的一个开源的高性能键值对&#xff08;key-value&#xff09;数据库&#xff0…

C语言sprintf函数使用

1 其函数原型为&#xff1a;int sprintf(char *str, const char *format,...)。 具体用法如下&#xff1a; 基本语法&#xff1a; str&#xff1a;目标字符串的指针&#xff0c;用于存储格式化后的结果。format&#xff1a;格式化字符串&#xff0c;用于指定输出的格式。后续是…

数据结构-队列的介绍及循环队列

1.队列的概念 在开始前&#xff0c;请牢记这句话&#xff1a;队列是一个先进先出的数据结构。 队列&#xff08;queue&#xff09;是限定在表的一端进行插入&#xff0c;表的另一端进行删除的数据结构&#xff0c;如同栈的学习&#xff0c;请联系前文所学链表&#xff0c;试想…

4.5SQL注入之加解密注入

SQL注入之加解密注入Base64是网络上最常见的用于传输8Bit字节码的编码方式之一&#xff0c;Base64就是一种基于64个可打印字符来表示二进制数据的方法。 Less-21关 Cookie加密注入&#xff1a; 通过Burpsuite抓包&#xff1a; 进行Base64解密&#xff1a;

波场(Tron)监听区块交易(TRX,USDT)

前言说明&#xff1a; 本篇文章参考GitHub一位伙伴的代码&#xff0c;再代码基础上优化改良以后的结果&#xff0c;但是一下找不到那位大佬的GitHub链接了&#xff0c;如有侵权请联系作者调整文章&#xff0c;让跟多人收益。谢谢。 实现思路: 波场链是一条很新奇的链&#xff…