学习思路:
- ✔️2 个简单的预备知识
- ✔️http 请求和响应 格式画出来,两个工具见一见 http 请求/响应的样子
- 写一个最简单的 httpserver,用浏览器直接测试
- 开始研究 http 的细节字段--回归理论+http code
- 谈 http 报文细节
对比思考:
编码和解码 | 序列化和反序列化
相同点:
- 都是数据处理的过程,涉及到数据的转换。
- 都有一个逆过程,编码对应解码,序列化对应反序列化。
不同点:
- 目的不同:编码通常是为了数据的传输或存储的兼容性,而解码是为了恢复原始数据;序列化是为了保存对象的状态,反序列化是为了恢复对象的状态。
- 处理的数据类型不同:编码通常处理基本数据类型(如字符、字节等),而序列化处理的是复杂的数据结构(如对象、数组等)。
- 复杂度不同:序列化通常比编码更复杂,因为它需要处理对象之间的引用关系、类型信息等。
- 上下文不同:编码和解码更多地在字节和字符层面操作,序列化和反序列化则与特定的编程语言和对象模型相关。
总的来说,编码和解码是序列化和反序列化的一个子集,序列化和反序列化包含了编码和解码的过程,但涉及更复杂的结构和状态转换。
一. 预备知识
服务器的设计原则与常见协议
在之前的学习中,我们已经完成了基于 Socket 的基本服务器实现,并且通过多进程、多线程、线程池等模式处理并发请求。我们还了解了如何使用自定义协议进行通信,结合序列化和反序列化处理数据。这些知识让我们具备了开发基础的网络应用的能力。
那么,是否有针对常见场景的现成协议软件可以直接使用呢?答案是肯定的,最典型的例子就是 HTTP 协议。未来我们使用 HTTP 做的事情,本质上和我们之前做的一样,只不过 HTTP 协议是为特定的应用场景而设计的。
OSI 七层模型和 TCP/IP 模型
在网络基础中,我们知道 OSI 模型将网络通信划分为七层:应用层、表示层、会话层等。而在 TCP/IP 协议中,应用层、表示层和会话层通常被合并为一层,称为应用层。
当我们设计网络版的计数器应用时,实际上也将功能划分为三层:
- 会话层:处理获取连接、启动多进程、多线程或线程池。
- 表示层:负责读取完整报文、提取有效载荷,并进行序列化与反序列化。
- 应用层:处理具体业务逻辑(即回调函数
callback
)。
实际上,OSI 模型中的七层划分是为了编码时保持层次结构的清晰性。比如表示层有多种方案:自定义协议、JSON、Protobuf、XML 等。这些并没有被固定到操作系统内核中,使得开发者能够灵活选择适合的表示层方案。
HTTP 协议
虽然我们可能对 HTTP 还不够了解,但可以确定,HTTP 协议中肯定包含了以下几方面:
- 使用套接字进行通信。
- 具备序列化和反序列化的机制。
- 包含报头的添加和解析过程。
HTTP 协议作为应用层协议,也必须处理与我们所讨论的相同的三项任务:
- 解析 URL。
- 处理客户端与服务器之间的请求与响应。
- 根据请求路径返回文件资源。
1. URL 的结构
常见的 URL 结构如下:
https://blog.csdn.net/fight_p/article/details/137103487
- https:协议(HTTP 或 HTTPS)。
- blog.csdn.net:域名,经过 DNS 解析后转换为服务器的 IP 地址。
- /fight_p/article/details/137103487:文件路径,指向服务器上的某个资源。
完整如下,之后会详细解释:
浏览器通过这个 URL 找到对应的服务器,并请求该路径下的资源。值得注意的是,URL 中可以没有明确指定端口号,但服务器必须绑定到众所周知的端口(例如 HTTP 使用端口 80,HTTPS 使用端口 443)。如果 URL 中没有显示指定端口号,浏览器会根据协议自动填充。
2. HTTP 是超文本传输协议
HTTP 协议的本质是从服务器获取文件资源。资源可以是:
- 图片、视频、音频等文件。
- HTML、CSS、JavaScript 文件。
- API 接口返回的数据。
无论是哪种资源,它们最终都存储在服务器的某个路径下,而 HTTP 协议则负责根据客户端的请求,定位并返回这些资源。
3. URL 编码与解码
在 URL 中,一些特殊字符(如
/
,
?
,
:
等)具有特定的含义,因此不能直接出现在请求的参数中。这些字符在传递时需要进行 URL 编码。编码后的字符以
%XY
的形式表示,其中
XY
是字符的 16 进制表示。
编码规则如下:
- 将需要编码的字符转换为 16 进制。
- 每个字符占 8 位,从右到左取 4 位转成 16 进制数。
- 16 进制数前面加
%
,形成%XY
格式。
解码 则是将
%XY
转回原始字符。
虽然我们可以从头开始实现这个编码和解码过程,但实际上现成的编码和解码函数已经非常成熟,可以直接使用。我们可以在网上查找相关的 URL 解码源码,作为工程师使用即可。
总结:
二. HTTP 协议
1.原理
实现如下:
可以发现 HTTP 协议是由多个部分组成的,下面我们将逐一分析这些部分。
请求
- 请求行
HTTP请求的第一行被称为请求行,它由三部分组成:
- 请求方法:如GET、POST、PUT等,表示对资源的操作。
- URL:统一资源定位符,指定请求的资源。
- HTTP版本:常见的有HTTP/1.0、HTTP/1.1、HTTP/2.0等。 请求行以
\r\n
或\n
作为分隔符。
- 请求报头
请求报头是请求的第二大部分,由多行组成,每行包含一个属性,格式为
name:value
。这些属性提供了关于请求的额外信息,如客户端类型、请求内容类型等。
- 空行
紧随请求报头之后的是一个空行,这个空行非常重要,它标志着请求头的结束和请求正文的开始。
- 请求正文
请求的最后一部分是正文,这部分是可选的。例如,在提交表单数据或上传文件时,正文将包含这些数据。
一个完整的HTTP请求报文包括上述四大块,并通过TCP连接发送到服务器。
响应
HTTP响应的格式与请求格式非常相似,也分为四部分。
1.** 状态行**
响应的第一行是状态行,同样由三部分组成:
- HTTP版本:表明使用的HTTP协议版本。
- 状态码:如200、400、302、307、500、404等,用于表示请求的结果。
- 状态码描述:对状态码的文本描述,如404表示"Not Found",200表示"OK"。
2**. 响应报文**
响应报文由多行组成,包含了关于响应的额外信息,如内容类型、服务器类型等。
3.** 空行**
与请求格式一样,响应报文后也跟着一个空行。
4. 响应正文
响应正文中包含了从服务器返回的实际内容,通常是HTML、CSS、JS、图片、视频或音频等。
这四部分构成了HTTP响应报文,并通过TCP连接发送回客户端。
2. 基本工具(postman,fiddler)
- postman,不是抓包工具,模拟客户端 ----> 浏览器行为
postman可以认为就是把浏览器换成它发起请求然后服务器给响应。
- fiddler,是一个抓包工具,专门用来抓http的,抓的是本地的,可以用来调试的
fiddler原理就是,未来浏览器在发起请求时是把请求交给fiddler,由fiddler代替你去请求服务器,服务器响应也是给fiddler,然后fiddler再把响应转发给浏览器。
3. 代码验证
接下来,我们将通过编写代码来验证上述理论。我们将使用套接字(socket)来模拟HTTP请求和响应的过程。
# 示例代码,使用Python的socket库
import socket
# 创建socket对象
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 连接到服务器
client_socket.connect(('www.example.com', 80))
# 发送HTTP请求
request = "GET / HTTP/1.1\r\nHost: www.example.com\r\n\r\n"
client_socket.send(request.encode())
# 接收响应
response = b''
while True:
part = client_socket.recv(1024)
if not part:
break
response += part
# 打印响应内容
print(response.decode())
# 关闭连接
client_socket.close()
基于上述代码进行完善,我们可以看到如何通过套接字发送HTTP请求并接收响应,从而验证我们对HTTP协议格式的理解,下篇文章将 完整的实现自定义 http协议~
版权归原作者 lvy- 所有, 如有侵权,请联系我们删除。