文章目录
- 前言
- 1. 应用层自定义协议与序列化
- 1.1 什么是应用层?
- 1.2 再谈 "协议"
- 1.3 序列化 和 反序列化
- 2. HTTP 协议
- 3. 认识 URL(统一资源定位符)
- 4. urlencode和urldecode
- 5. HTTP 协议请求与响应格式
- 5.1 HTTP 请求
- 5.2 HTTP 响应
- 6. HTTP 的方法
- 6.1 GET 方法
- 6.2 POST 方法
- 6.3 POST 与 GET 比较
- 7. HTTP的状态码和header
- 7.1 状态码的本质就是一个整数,常见的状态码:
- 7.2 HTTP常见的header:
- 8. HTTP cookie 与 session
- 8.1 引入 HTTP Cookie
- 8.2 引入 HTTP Session
- 8.3 Cookie 与 Session
- 总结
前言
在现代计算机网络通信中,应用层协议扮演着至关重要的角色,它们定义了客户端和服务器之间如何交换数据。本文将深入探讨应用层自定义协议与序列化技术,并详细解析HTTP协议,这是互联网上使用最广泛的应用层协议之一。通过本文,读者将能够理解应用层的概念、协议的重要性、序列化与反序列化的过程,以及HTTP协议的工作原理和相关技术细节。
1. 应用层自定义协议与序列化
1.1 什么是应用层?
我们程序员写的一个个解决我们实际问题, 满足我们日常需求的网络程序, 都是在应用层。
1.2 再谈 “协议”
协议是一种 “约定”. socket api 的接口, 在读写数据时, 都是按 “字符串” 的方式来发送接收的. 如果我们要传输一些 “结构化的数据” 怎么办呢?
其实,协议就是双方约定好的结构化的数据。
1.3 序列化 和 反序列化
TCP协议中, 数据在网络中传输是以字节流的形式, 然而我们想发给对端的数据可不一定是单纯的字符串, 有可能是结构体数据.
- 打个比方:
一个网络版本的计算机, 用户输入操作数和操作符后,会通过网络发给服务器, 比如:
用户想计算1+2,那么它可能会使用一个结构体保存操作数和操作符, 并且可能会使用一个结构体来保存计算后返回后的结果和错误描述:
class req
{
float left;//左操作数
char op;//操作符
float right;//右操作数
};
class rsp
{
float ret;//返回结果
string comment;//返回的错误描述
};
但是我们进行网络传输时不能直接传输结构体数据,必须先把结构体数据转换成字节流才能发送到网络, 同理,得到的结果也不可能是一个i结构体数据, 而是一段字节流, 我们需要想办法将结构体数据转化为字节流,这个过程称为序列化过程. 将字节流的数据转换为结构体数据的过程叫反序列化。
并且由于TCP协议发包时, 一个完整的数据可能会分多次发送过去, 所以我们一个完整的字节流数据不能只有数据,还需要有一些特殊的符号来标识一个数据的开始和结尾.这里我们可以自己制定协议,用前后三个问好标识数据的完整性
聪明的你可能已经发现了, 不仅仅需要特殊符号来标识数据的完整性, 来需要一些特殊符号来将结构体中的不同字段分隔开来。今天的示例中结构体的数据很少, 我们可以自己制定协议, 只要服务器和客户端都按照我们制定的协议进行序列化和反序列化也可以正常工作。 但是一旦遇见一个结构体有很多字段,甚至传递数组类型时,我们自己设定的方案未免太简陋了,所以这里给出几个常用的序列化/反序列化工具:
- json 有字符串,整型,布尔类型, 数组, 对象等数据类型
{ "firstName": "Brett", "lastName":"McLaughlin", "email": "brett@newInstance.com" }
json是以key:value的格式来序列化的,比如我们的示例中:
{ "left" : 1, "op" : "+", "right" : 2}
- XML, 和 json 类似
<person age="too young" experience="too simple" result="sometimes naive" />
或者这样:
<person>
<age value="too young" />
<experience value="too simple" />
<result value="sometimes naive" />
</person>
2. HTTP 协议
虽然我们说, 应用层协议是我们程序猿自己定的. 但实际上, 已经有大佬们定义了一些现成的, 又非常好用的应用层协议, 供我们直接参考使用. HTTP(超文本传输协议)就是其中之一。
在互联网世界中,HTTP(HyperText Transfer Protocol,超文本传输协议)是一个至关重要的协议。它定义了客户端(如浏览器)与服务器之间如何通信,以交换或传输超文本(如 HTML 文档)。
HTTP 协议是客户端与服务器之间通信的基础。客户端通过 HTTP 协议向服务器发送请求,服务器收到请求后处理并返回响应。HTTP 协议是一个无连接、无状态的协议,即每次请求都需要建立新的连接,且服务器不会保存客户端的状态信息。
3. 认识 URL(统一资源定位符)
- URL的定义:URL是互联网上资源的地址,类似于我们日常所说的“网址”。
- 网络通信与IO:网络通信实际上就是IO通信,我们从服务器上获取下来的,都叫资源!
- 资源的位置:我们没有获取资源之前,这些资源在哪里?服务器
- 资源与文件的关系:所有资源,在Linux 中都是文件! 获取文件,找到对应的文件。
- 服务器的定位:找到对应的文件,先找到文件所在的服务器(IP+[Port]),所有文件都有路径(/a/b/c.xxx)!
- URL的构成:IP[port] +路径,不就可以表示互联网中唯一的一个文件(资源)吗?
- URL中"/"的作用:URL 中 / 就相当于Linux中的路径分隔符!
4. urlencode和urldecode
像 / ?
: 等这样的字符, 已经被url当做特殊意义理解了. 因此这些字符不能随意出现。
比如, 某个参数中需要带有这些特殊字符, 就必须先对特殊字符进行转义。
转义的规则如下:
将需要转码的字符转为16进制,然后从右到左,取4位(不足4位直接处理),每2位做一位,前面加上%,编码成%XY格式。
- 例如:
“+
” 被转义成了 “%2B
”
urldecode 就是 urlencode 的逆过程;
5. HTTP 协议请求与响应格式
5.1 HTTP 请求
真实的HTTP请求格式:
- 首行: [方法] + [url] + [版本]
- Header: 请求的属性, 冒号分割的键值对;每组属性之间使用\r\n 分隔;遇到空行表示 Header 部分结束。
- Body: 空行后面的内容都是 Body. Body 允许为空字符串. 如果 Body 存在, 则在Header 中会有一个 Content-Length 属性来标识 Body 的长度;
5.2 HTTP 响应
真实的HTTP响应格式:
- 首行: [版本号] + [状态码] + [状态码解释]
- Header: 请求的属性, 冒号分割的键值对;每组属性之间使用\r\n 分隔;遇到空行表示 Header 部分结束
- Body: 空行后面的内容都是 Body. Body 允许为空字符串. 如果 Body 存在, 则在Header 中会有一个 Content-Length 属性来标识 Body 的长度; 如果服务器返回了一个 html 页面, 那么 html 页面内容就是在
body 中.
6. HTTP 的方法
其中最常用的就是 GET 方法和 POST 方法.
6.1 GET 方法
- 用途:用于请求URL指定的资源。
- 示例: GET /index.html HTTP/1.1
- 特性:指定资源经服务器端解析后返回响应内容。
- form 表单:https://www.runoob.com/html/html-forms.html
6.2 POST 方法
- 用途:用于传输实体的主体,通常用于提交表单数据。
- 示例:POST /submit.cgi HTTP/1.1
- 特性:可以发送大量的数据给服务器,并且数据包含在请求体中。
- form 表单:https://www.runoob.com/html/html-forms.html
6.3 POST 与 GET 比较
- GET 方法通过URL传参,会回显输入的私密信息,不够私密
- POST 方法通过正文提交参数,不回显,比较私密
- 请注意,这里的私密并不是指安全性能得到保证,保证安全性是需要通过加密
7. HTTP的状态码和header
7.1 状态码的本质就是一个整数,常见的状态码:
- 200 表示ok,请求正常处理完毕
- 404 这个相信大家很熟悉,就是没找到服务
- 505 表示服务器内部错误
7.2 HTTP常见的header:
- Host: 客户端告知服务器, 所请求的资源是在哪个主机的哪个端口上;
- User-Agent: 声明用户的操作系统和浏览器版本信息;
- referer: 当前页面是从哪个页面跳转过来的;
- Location: 搭配 3xx 状态码使用, 告诉客户端接下来要去哪里访问;
- Cookie: 用于在客户端存储少量信息. 通常用于实现会话(session)的功能;
8. HTTP cookie 与 session
- 问题:B 站是如何认识我这个登录用户的?
- 问题:HTTP 是无状态,无连接的,怎么能够记住我?
HTTP 协议是无状态,无连接的。
网站需要进行标识身份!
解决方法:cookie 和 session 技术!(登录会话管理)
8.1 引入 HTTP Cookie
定义:
HTTP Cookie(也称为 Web Cookie、浏览器 Cookie 或简称 Cookie)是服务器发送到用户浏览器并保存在浏览器上的一小块数据,它会在浏览器之后向同一服务器再次发起请求时被携带并发送到服务器上。通常,它用于告知服务端两个请求是否来自同一浏览器,如保持用户的登录状态、记录用户偏好等。
工作原理:
- 当用户第一次访问网站时,服务器会在响应的 HTTP 头中设置 Set-Cookie字段,用于发送 Cookie 到用户的浏览器。
- 浏览器在接收到 Cookie 后,会将其保存在本地(通常是按照域名进行存储)。
- 在之后的请求中,浏览器会自动在 HTTP 请求头中携带 Cookie 字段,将之前保存的 Cookie 信息发送给服务器。
分类:
- 会话 Cookie(Session Cookie):在浏览器关闭时失效。
- 持久 Cookie(Persistent Cookie):带有明确的过期日期或持续时间,可以跨多个浏览器会话存在。
- 如果 cookie 是一个持久性的 cookie,那么它其实就是浏览器相关的,特定目录下的一个文件。但直接查看这些文件可能会看到乱码或无法读取的内容,因为 cookie 文件通常以二进制或 sqlite 格式存储。一般我们查看,直接在浏览器对应的选项中直接查看即可。
类似于下面这种方式:
安全性:
- 由于 Cookie 是存储在客户端的,因此存在被篡改或窃取的风险。
单独使用 Cookie,有什么问题?
- 我们写入的是测试数据,如果写入的是用户的私密数据呢?比如,用户名密码,浏览痕迹等。
- 本质问题在于这些用户私密数据在浏览器(用户端)保存,非常容易被人盗取,更重要的是,除了被盗取,还有就是用户私密数据也就泄漏了。
8.2 引入 HTTP Session
定义:
HTTP Session 是服务器用来跟踪用户与服务器交互期间用户状态的机制。由于 HTTP协议是无状态的(每个请求都是独立的),因此服务器需要通过 Session 来记住用户的信息。
工作原理:
当用户首次访问网站时,服务器会为用户创建一个唯一的 Session ID,并通过Cookie 将其发送到客户端。
客户端在之后的请求中会携带这个 Session ID,服务器通过 Session ID 来识别用户,从而获取用户的会话信息。
服务器通常会将 Session 信息存储在内存、数据库或缓存中。
安全性:
与 Cookie 相似,由于 Session ID 是在客户端和服务器之间传递的,因此也存在被窃取的风险。
但是一般虽然 Cookie 被盗取了,但是用户只泄漏了一个 Session ID,私密信息暂时没有被泄露的风险Session ID 便于服务端进行客户端有效性的管理,比如异地登录。可以通过 HTTPS 和设置合适的 Cookie 属性(如 HttpOnly 和 Secure)来增强安全性。
超时和失效:
Session 可以设置超时时间,当超过这个时间后,Session 会自动失效。
服务器也可以主动使 Session 失效,例如当用户登出时。
用途:
用户认证和会话管理
存储用户的临时数据(如购物车内容)
实现分布式系统的会话共享(通过将会话数据存储在共享数据库或缓存中)
- 实际会话保持的做法是:cookie + session!
8.3 Cookie 与 Session
session 相对安全的!sessionid 也是可能被盗取的!
- 什么被冒认:
session(服务器创建,服务器管理的!,只要让sessionid 失效就可以了!)
你怎么知道这个client对应的session是一个非法的?(和业务结合) - 信息泄漏
总结
本文全面介绍了应用层自定义协议与序列化技术,详细解释了HTTP协议的工作原理、URL的构成、urlencode和urldecode的转义规则、HTTP请求与响应的格式、HTTP方法的特性、状态码和header的作用,以及cookie与session在会话管理中的应用。通过这些知识点,读者可以更好地理解网络通信的底层机制,为开发高效、安全的网络应用程序打下坚实的基础。
文章首先介绍了应用层的概念,解释了协议作为通信双方约定的数据结构的重要性,并探讨了数据在网络中传输时的序列化与反序列化过程。接着,文章深入分析了HTTP协议,包括其请求与响应的格式、常见的HTTP方法如GET和POST,以及状态码和header的使用。文章还特别强调了HTTP协议的无状态特性,以及如何通过cookie和session技术来实现会话管理。
在文章的最后部分,对cookie和session进行了详细的比较和分析,讨论了它们的工作原理、分类、安全性问题以及在实际开发中的应用。通过这些内容,读者不仅能够掌握理论知识,还能够了解如何将这些技术应用到实际的网络编程中,提高应用程序的性能和安全性。
总的来说,本文为读者提供了一个全面的网络通信知识框架,从应用层协议的设计到HTTP协议的具体实现,再到会话管理的技术细节,为读者在网络编程领域的学习和实践提供了宝贵的指导。