当前位置: 首页 > news >正文

应用层协议 --- HTTP

序言

 在上一篇文章中,我们在应用层实现了一个非常简单的自定义协议,我们在我们报文的首部添加了报文的长度并且使用特定的符号分割。但是想做一个成熟,完善的协议是不简单的,今天我们就一起看看我们每天都会用到的 HTTP协议


URL

1.再识 URL

 刚接触电脑时我们肯定就会了解到 URL,我们一般称他为 网址,我们利用网址来定位网络上的特定资源。但是现在我们开始接触计网了,还应该认识他的本质了。
 在之前的内容中我们知道,所谓网络通信不过就是 物理距离增加后的 进程间通信。想要和网络上的某个设备的进程进行通信,我们需要知道该设备的 IP 地址和端口号IP地址 用于将数据发送到该设备上,端口号 用于将数据发送到指定进程。
 所以我们可以合理的推测 URL 的背后运行逻辑也是这样,但是我们一般的网址都是:

https://www.baidu.com/

没有你说的 IP,端口 呀?这是因为我们还需要 DNS,网址中的域名部分通过 DNS 系统被解析成 IP 地址。DNS 是一个分布式数据库,负责将人类可读的域名转换成机器可读的 IP 地址。
 这样做的原因是 网址提供了一种更加用户友好的方式来定位和访问这些资源。通过域名系统和默认的端口号约定,用户可以在不知道具体IP地址和端口号的情况下,轻松地访问他们想要的网络资源。

2. URL 的组成

 现在我使用百度的搜索引擎输出一个 你好URL 生成如下:
在这里插入图片描述
输出一个简单的 你好 竟然这么长,我们来层次的划分理解一下:

  • 协议部分指定了用于访问资源的应用层协议,如 HTTP、HTTPS、FTP
  • 域名部分代表了资源所在的主机或服务器的名称
  • 路径部分指定了服务器上资源的具体位置,帮助服务器定位到用户请求的具体资源
  • 参数部分用于向服务器传递额外的信息,以便服务器根据信息返回更精确的结果

在这里重点介绍一下 路径部分,当我们只是输入一个域名时我们可以在后面加上具体要访问的资源的路径,但是如果我们没有加上的话,他会自动跟一个 \。咦?这不是根目录吗?不是的,服务端接收后会处理你的路径,方法各有不同,但是常见的是将 \ 替换为他首页的页面路径,就拿百度举例:
在这里插入图片描述


HTTP 协议

1. 什么是 HTTP

 在互联网世界中,HTTP(HyperTextTransferProtocol,超文本传输协议)是一个至关重要的协议。它定义了 客户端(如浏览器)与服务器之间如何通信,以交换或传输超文本(如 HTML 文档)。经过前面的的铺垫学习,我们知道了只要是协议,双方就达成了一定的约定!
 在这里还需要注意重要的一点是,HTTP 的底层是基于 TCP 进行数据传输的!

2. HTTP 的请求与响应

2.1 请求报头

 现在我们做一个简单的试验,我们在云服务器上运行我们的服务端程序,并在本地的浏览器上使用 IP + 端口号 的形式访问,可以看到服务端输出:
在这里插入图片描述
很奇怪,我们并没有发送任何的内容,这是哪里来的呀?大家别忘了,浏览器在应用层,发送信息是会对报文增添报头,即使报文为空!这里输出的内容,就是 HTTP 协议约定好的报头!!!

 现在我们来看一下标准格式的请求头:
在这里插入图片描述

我们来了解一下请求行的作用:

  • 请求方法
    GET: 请求指定的资源,我们用的最多的方式
    POST:向服务器提交数据,比如登陆账号信息,会将具体的信息放在正文中
  • URL:这指定了请求的资源的路径,前面介绍过
  • HTTP版本:指定了客户端使用的 HTTP 协议版本,告诉服务器客户端能够理解的协议特性

请求报头数量是非常多的,并且很多都是需要特定的使用场景,我们只是介绍常用的报头:

  • Host: 指定请求的服务器的域名和端口号
  • User-Agent: 包含了发出请求的用户代理软件信息,通常是浏览器
  • Accept: 告诉服务器可以发送哪些媒体类型的内容
  • Content-Length: 请求体的长度
  • Cookie:缓存部分用户信息

 在这里可能需要阐明一点,如果你的请求方式为 GET,也是可以传递数据的。咦?不应该使用 POST吗?两个都行!比如搜索引擎,我们需要向输入框内输入搜索查询内容吧,我们的输入的内容就会以参数的格式加在 URL 后面。所以只是两者的方式不同,前者是将传递数据放在正文中,后者是放在 URL 中。
Cookie 非常重要,在后面会专门写一篇文章来进行说明,今天重要的是大体介绍 HTTP 的内容。

2.2 响应报头

 有了请求报文,现在我们再获取一下响应报文(在这里并没有找到一个很好抓包的方法,使用 AI 生成了一个效果一样的,嘻嘻):
在这里插入图片描述

响应报文的标准格式如下:
在这里插入图片描述
HTTP版本 就不多阐述了,我们重点其他内容,首先是状态码和状态码阐述:
在这里插入图片描述
一共包含 5 类,每一类的作用都大不相同,我们介绍最常见的状态码:

  • 200 OK:请求已成功,请求所希望的响应头或数据体将随此响应返回
  • 404 Not Found:服务器无法找到请求的资源。在浏览器中,这意味着 URL 输入错误或请求的页面已经被移除或不存在
  • 403 Forbidden:服务器理解请求,但拒绝执行它,通常都是权限不够
  • 302 Found (Redirect):请求的资源临时移动到了另一个 URI。客户端应该使用 GET 方法访问新的 URI ,原始请求的方法可能不再适用
  • 504 Gateway Timeout:作为网关或代理的服务器在等待上游服务器的响应时超时

原来这就是当我们搜索出错时弹出来的状态码的意义呀!最后便是我们的报头数据了:

  • Content-Type:指示响应主体的数据类型
  • Content-Length:指示响应主体的长度,以字节为单位
  • Date:指示响应生成的日期和时间

实现 HTTP 响应

 首先我们来分析一下在应用层数据需要怎么处理:
在这里插入图片描述

  1. 首先,本地将请求序列化发送给服务端特定端口
  2. 服务端接收请求数据并反序列化,处理后得到相应的响应数据
  3. 服务端将响应数据序列化发送给客户端特定端口
  4. 客户端接受响应数据并反序列化,得到结果

结果分析,看起来我们需要完成请求数据的序列化和反序列化,响应数据的序列化和反序列化。但是其实 请求数据的序列化和响应数据反序列化 浏览器已经帮我们做了!当你访问一个 URL 时其实已经将请求数据序列化并发送了!根据你的搜索呈现相应的结果不就是响应数据的反序列化吗?

 明白了这些,咋们直接开敲,首先肯定是构建 TCP注意:HTTP协议的底层使用的是 TCP 协议,如果你使用 UDP 是不能正常沟通的!!!) 的创建套接字文件:

// 创建套接字文件
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd < 0)
{perror("socket:");exit(1);
}
std::cout << "Successful create sockfd..." << std::endl;

 之后便是绑定:

 // 绑定struct sockaddr_in Address;Address.sin_family = AF_INET;Address.sin_addr.s_addr = INADDR_ANY;Address.sin_port = htons(PORT);int n = bind(sockfd, (struct sockaddr*)&Address, sizeof(Address));if(n < 0){perror("bind::");exit(1);}std::cout << "Successful bind..." << std::endl;

再者就是监听和接受连接:

// 监听
n = listen(sockfd, 3);
if(n < 0)
{perror("listen:");exit(1);
}
std::cout << "Successful listening..." << std::endl;// 等待接收连接
struct sockaddr_in ClientAddress;
socklen_t len = sizeof(ClientAddress);
int newfd = accept(sockfd,  (struct sockaddr*)&ClientAddress, &len);
if(newfd < 0)
{perror("accept:");exit(1);
}
std::cout << "Successful accept..." << std::endl;

这都是几乎比较固定的步骤!咋们对特定的业务只需要对数据处理模块进行特定的设计,现在我想要返回一个类似于网页的界面,就简单一下让人工智能帮咋们设计一下:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>你好</title>
<style>@keyframes bounce {0%, 20%, 50%, 80%, 100% {transform: translateY(0);}40% {transform: translateY(-30px);}60% {transform: translateY(-15px);}}.bounce-text {font-size: 24px;animation: bounce 2s infinite;}
</style>
</head>
<body><div class="bounce-text">你好</div></body>
</html>

 现在当我们和客户端顺利连接时,咋们就按照协议的要求发送该内容:

std::string Content = GetIndex();
while(true)
{std::string response;response += "HTTP/1.0 200 OK\n";response += "Content-Length:" + std::to_string(Content.size()) + '\n';response += '\n'+ Content;send(newfd, response.c_str(), response.size(), 0);
}

我们简单的添加了状态行和响应报头最后是我们的上述 html 的内容,最后看一下效果:
在这里插入图片描述
成功啦,也不难是吧!


总结

 在这篇文章中我们简单认识了 HTTP 协议的组成,并且已经简单的实现了浏览器访问云服务器,返回相应数据的功能,希望大家有所收获!

相关文章:

应用层协议 --- HTTP

序言 在上一篇文章中&#xff0c;我们在应用层实现了一个非常简单的自定义协议&#xff0c;我们在我们报文的首部添加了报文的长度并且使用特定的符号分割。但是想做一个成熟&#xff0c;完善的协议是不简单的&#xff0c;今天我们就一起看看我们每天都会用到的 HTTP协议 。 UR…...

网卡Network Interface Card

文章目录 网卡&#xff08;Network Interface Card&#xff0c;简称NIC&#xff09;是一种计算机硬件设备&#xff0c;用于将计算机连接到计算机网络&#xff0c;使计算机能够进行数据通信。它是计算机与外部网络&#xff08;如局域网、互联网&#xff09;之间的接口&#xff0…...

9.1 Linux_I/O_基本知识

文件类型 一切I/O皆文件&#xff0c;文件就是存放在磁盘上面的有序数据的集合。 文件类型&#xff1a; 常规文件 r &#xff1a;就是普通文件目录文件 d &#xff1a;就是目录&#xff0c;是一个索引字符设备文件 c &#xff1a;键盘、鼠标块设备文件 b &#xff1a;U盘、磁…...

[Java]一、面向对象核心编程思想

G:\Java\1.JavaSE 1. 继承 1.1 继承的概述 重点内容:1.知道继承的好处2.会使用继承3.知道继承之后成员变量以及成员方法的访问特点4.会方法的重写,以及知道方法重写的使用场景5.会使用this关键字调用当前对象中的成员6.会使用super关键字调用父类中的成员7.会定义抽象方法以…...

科研绘图系列:R语言多个AUC曲线图(multiple AUC curves)

文章目录 介绍加载R包导入数据数据预处理画图输出结果组图系统信息介绍 多个ROC曲线在同一张图上可以直观地展示和比较不同模型或方法的性能。这种图通常被称为ROC曲线图,它通过比较不同模型的ROC曲线下的面积(AUC)大小来比较模型的优劣。AUC值越大,模型的诊断或预测效果越…...

JavaWeb--纯小白笔记06:使用Idea创建Web项目,Servlet生命周期,注解,中文乱码解决

使用Idea创建一个web项目----详细步骤配置&#xff0c;传送门&#xff1a;http://t.csdnimg.cn/RsOs7 src&#xff1a;放class文件 web&#xff1a;放html文件 out&#xff1a;运行过后产生的文件 一创建一个新的web项目(配置好了后)&#xff1a; 在src创建一个文件…...

jQuery——jQuery的2把利器

1、jQuery 核心函数 ① 简称&#xff1a;jQuery 函数&#xff0c;即为 $ 或者 jQuery ② jQuery 库向外直接暴露的是 $ 或者 jQuery ③ 引入 jQuery 库后&#xff0c;直接使用 $ 即可 当函数用&#xff1a;$&#xff08;xxx&#xff09; 当对象用&#xff1a;$.xxx&#x…...

Day29笔记-Python操作pdfPython发送邮件

一、Python操作PDF【了解】 1.pdf 简介 PDF是Portable Document Format的缩写&#xff0c;这类文件通常使用.pdf作为其扩展名。在日常开发工作中&#xff0c;最容易遇到的就是从PDF中读取文本内容以及用已有的内容生成PDF文档这两个任务。 在Python中&#xff0c;可以使用名为P…...

Seata分布式事务实践

理论篇 什么是事务 关于事务我们一定会想到下面这四大特性: 原子性:所有操作要么全都完成&#xff0c;要么全都失败。 一致性: 保证数据库中的完整性约束和声明性约束。 隔离性:对统一资源的操作不会同时发生的。 持久性:对事务完成的操作最终会持久化到数据库中。 理解&…...

数字IC设计\FPGA 职位经典笔试面试整理--基础篇2

1. 卡诺图 逻辑函数表达式可以使用其最小项相加来表示&#xff0c;用所有的最小项可以转换为卡诺图进行逻辑项化简 卡诺图讲解资料1 卡诺图讲解资料2 卡诺图讲解资料3 最小项的定义 一个函数的某个乘积项包含了函数的全部变量&#xff0c;其中每个变量都以原变量或反变量的形…...

(务必收藏)推荐市面上8款AI自动写文献综述的网站

在当前的学术研究和论文写作中&#xff0c;AI技术的应用已经变得越来越普遍。特别是在文献综述这一环节&#xff0c;AI工具能够显著提高效率并减少人工劳动。以下是市面上8款推荐的AI自动写文献综述的网站&#xff1a; 一、千笔-AIPassPaper 是一款备受好评的AI论文写作平台&…...

【python】运算符

学习目标 了解 Python 中常见 算术&#xff08;数学&#xff09;运算符赋值运算符 算术&#xff08;数学&#xff09;运算符 a 是 10&#xff0c;b 是 20 运算符描述实例加两个对象相加 a b 输出结果 30-减得到负数或是一个数减去另一个数 a - b 输出结果 -10*乘两个数相…...

C++深入学习string类成员函数(1):默认与迭代

引言 在 C 编程中&#xff0c;std::string 类是处理字符串的核心工具之一。作为一个动态管理字符数组的类&#xff0c;它不仅提供了丰富的功能&#xff0c;还通过高效的内存管理和操作接口&#xff0c;极大地方便了字符串操作。通过深入探讨 std::string 的各类成员函数&#…...

DataGrip远程连接Hive

学会用datagrip远程操作hive 连接前提条件&#xff1a; 注意&#xff1a;mysql是否是开启状态 启动hadoop集群 start-all.sh 1、启动hiveserver2服务 nohup hiveserver2 >> /usr/local/soft/hive-3.1.3/hiveserver2.log 2>&1 & 2、beeline连接 beelin…...

go 读取excel

一、安装依赖 go get github.com/tealeg/xlsx二、main.go package mainimport "fmt" import "github.com/tealeg/xlsx"type Student struct {Name stringSex string }func (student Student) show() {fmt.Printf("Name:%s Sex:%s\r\n", stude…...

Linux进阶系列(四)——awk、sed、端口管理、crontab

目录 1. 写在前面2. awk —— 强大的文本处理工具2.1 awk 概述2.2 awk 脚本结构2.3 awk 的内置变量2.4 awk 的高级用法2.5 awk实践 3. sed —— 流式文本编辑器3.1 sed 的基本语法3.2 sed 常用命令3.3 sed 的高级用法 4. Linux 端口管理4.1 端口的概念4.2 查看端口状态4.3 开放…...

利用Metasploit进行信息收集与扫描

Metasploit之信息收集和扫描 在本文中&#xff0c;我们将学习以下内容 使用Metasploit被动收集信息 使用Metasploit主动收集信息 使用Nmap进行端口扫描 使用db_nmap方式进行端口扫描 使用ARP进行主机发现 UDP服务探测 SMB扫描和枚举 SSH版本扫描 FTP扫描 SMTP枚举 …...

基于Pytorch框架的深度学习MODNet网络精细人像分割系统源码

第一步&#xff1a;准备数据 人像精细分割数据&#xff0c;可分割出头发丝&#xff0c;为PPM-100开源数据 第二步&#xff1a;搭建模型 MODNet网络结构如图所示&#xff0c;主要包含3个部分&#xff1a;semantic estimation&#xff08;S分支&#xff09;、detail prediction…...

Go语言中的并发编程

Go语言中的并发编程Go语言中的并发编程主要依赖于两个核心概念&#xff1a;goroutine 和 channel。1. Goroutinegoroutine 的特点结束 goroutine2. Channel创建 Channel发送和接收数据Channel 的类型使用 select 语句简单的多个 goroutine使用 WaitGroup 等待所有 goroutine 完…...

python学习笔记(3)——控制语句

控制语句 我们在前面学习的过程中&#xff0c;都是很短的示例代码&#xff0c;没有进行复杂的操作。现在&#xff0c;我们将开始学习流程控制语句。 前面学习的变量、数据类型&#xff08;整数、浮点数、布尔&#xff09;、序列&#xff08;字符串、列表、元组、字 典、集合&am…...

关系数据库设计之Armstrong公理详解

~犬&#x1f4f0;余~ “我欲贱而贵&#xff0c;愚而智&#xff0c;贫而富&#xff0c;可乎&#xff1f; 曰&#xff1a;其唯学乎” 一、Armstrong公理简介 Armstrong公理是一组在关系数据库理论中用于推导属性依赖的基本规则。这些公理是以著名计算机科学家威廉阿姆斯特朗&…...

【Geoserver使用】SRS处理选项

文章目录 前言一、Geoserver的三种SRS处理二、对Bounding Boxes计算的影响总结 前言 今天来看看Geoserver中发布图层时的坐标参考处理这一项。根据Geoserver官方文档&#xff0c;坐标参考系统 (CRS) 定义了地理参考空间数据与地球表面实际位置的关系。CRS 是更通用的模型&…...

python里面的单引号和双引号的区别

在Python中&#xff0c;单引号&#xff08;‘’&#xff09;和双引号&#xff08;“”&#xff09;在大多数情况下是等价的&#xff0c;没有本质区别。它们都用于创建字符串。以下是一些关键点&#xff1a; 功能相同&#xff1a; 两者都可以用来定义字符串&#xff0c;例如&…...

为什么不要在循环,条件或嵌套函数中调用hooks

为什么不要在循环&#xff0c;条件或嵌套函数中调用hooks 前言useState Hook 的工作原理具体实现1、初始化2、第一次渲染3、后续渲染4、事件处理简单代码实现 为什么顺序很重要Bad Component 第一次渲染Bad Component 第二次渲染 总结 前言 自从 React 推出 hooks 的 API 后&a…...

将成功请求的数据 放入apipost接口测试工具,发送给后端后,部分符号丢失

将成功请求的数据 放入apipost接口测试工具&#xff0c;发送给后端后&#xff0c;部分符号丢失 apipost、接口测试、符号、丢失、错乱、变成空格背景 做CA对接&#xff0c;保存CA系统的校验数据&#xff0c;需要模仿前端请求调起接口&#xff0c;以便测试功能完整性。 问题描…...

N诺计算机考研-错题

B A.LLC,逻辑链路控制子层。一个主机中可能有多个进程在运行,它们可能同时与其他的一些进程(在同一主机或多个主机中)进行通信。因此在一个主机的 LLC子层的一个服务访问点,以便向多个进程提供服务。B.MAC地址,称为物理地址、硬件地址,也称为局域网地址,用来定义网络设…...

vue3 数字滚动组件封装

相关参考文献 干货满满!如何优雅简洁地实现时钟翻牌器(支持JS/Vue/React) Vue3 插件方式 安装插件: countup.js 封装组件: components/count-up/index.js <template><div class="countup-wrap"><slot name="prefix"></slot&g…...

如何确保消息只被消费一次:Java实现详解

引言 在分布式系统中&#xff0c;消息传递是系统组件间通信的重要方式&#xff0c;而确保消息在传递过程中只被消费一次是一个关键问题。如果一个消息被多次消费&#xff0c;可能会导致业务逻辑重复执行&#xff0c;进而产生数据不一致、错误操作等问题。特别是在金融、电商等…...

Web3技术在元宇宙中的应用:从区块链到智能合约

随着元宇宙的兴起&#xff0c;Web3技术正逐渐成为其基础&#xff0c;推动着数字空间的重塑。元宇宙不仅是一个虚拟世界&#xff0c;它还代表着一个由去中心化技术驱动的新生态系统。在这个系统中&#xff0c;区块链和智能合约发挥着至关重要的作用&#xff0c;为用户提供安全、…...

关于QSizeGrip在ui界面存在布局的情况下的不显示问题

直接重写resizeEvent你会发现&#xff1a;grip并没有显示 void XXXXX::resizeEvent(QResizeEvent *event) {QWidget::resizeEvent(event);this->m_sizeGrip->move(this->width() - this->m_sizeGrip->width() - 3,this->height() - this->m_sizeGrip->…...