应用层传输层协议
应用层
序列化:指将多个数组对象按照指定格式组织成为二进制数据串,进行网络传输或持久化存储
反序列化:将二进制数据串按照指定格式进行解析得到数据对象
典型的序列化方式:json 序列化、protoBuf 序列化、二进制结构体序列化…
例子:结构体序列化
1、应用层:负责应用程序间的数据沟通(应用层协议由程序员定义)
2、自定制协议(如何设计一个协议) & 知名协议(HTTP、SMTP、FTP、SSH…)
3、需要考虑因素:传输性能、解析性能、调试便捷性
(1)传输性能:制定一个协议,传输的数据尽可能要短小,传输数据才能尽可能的快
(2)解析性能:传输多个数据对象时候需要进行序列化,对方拿到数据进行反序列化,解析性能指序列化与反序列化要足够的快
(3)调试便捷性:讨论的更多的是对于程序员的可见性、可识别性
4、使用结构体来设计传输协议:结构体天然的可以为我们设计数据格式以及数据在内存中进行排布
HTTP协议格式
HTTP协议:互联网公司中使用最多的协议,是一个 TCP 服务器,不过上层应用层协议使用的是HTTP协议的数据格式;是一个应用层协议,在传输层基于 TCP 协议
HTTP:超文本传输协议(最早期来传输 web 网页而设计)
优点:
1、基于字符串明文传输、调试便捷性高;
2、是一种简单的请求-响应协议(早期是短链接-一次请求响应结束就关闭);
3、基于TCP协议,传输安全可靠
请求格式
请求行、请求头部、空行、正文
(一)请求行(首部)
请求里边的第一行,主要对请求进行关键性描述
请求行中内容分三部分,以空格作为间隔,请求行以 \r\n 作为结尾 : 请求方法 URL 协议版本\r\n
第一部分:请求方法,实现不同的请求目的
GET: 向服务器请求一个网页实体资源,请求中没有正文,但是也可以向服务器提交数据,提交的数据在 URL 中(安全性低,长度受限)
POST: 向服务器提交表单数据,实现某个功能,请求中有正文
HEAD: 目的与 GET 类似(区分 GET / HEAD),不同的是,实际的响应中不要实体资源,只响应头部
PUT: 更新服务器上的资源
DELETE: 删除服务器上的资源
…
第二部分:URL
URL : 统一资源定位符,其实就是“网址”,定位网络上某一台主机上的某个资源(URL 不区分大小写)
HTTP 协议默认采用端口号 80 , HTTPS 默认端口号 443
第三部分:协议版本
描述了当前请求所使用的 HTTP 协议版本,不同版本之间有功能支持力度上的差异
HTTP协议版本迭代:
(1)HTTP/0.9 :0.9版本,是一个不成熟版本,只能使用 GET 获取网页,且没有当前完善的协议格式
(2)HTTP/1.0 :1.0版本,完善了协议格式,新增支持了更多请求方法:GET\HEAD\POST,以及流媒体的传输,且有了缓存控制
(3)HTTP/1.1 :1.1版本,当前用的最多的版本,新增支持了请求方法:PUT\DELETE…,针对当前网络,觉得以前的通信效率太低了,支持了长连接,对缓存的管理更加精细(静态资源的缓存管理、DNS服务器–内容分发网络、代理服务器缓存管理)
HTTP/1.1版本更多的是对传输效率的改进
(4)HTTP/2 :并不向前兼容
1、使用二进制传输(以前明文传输);
2、不用重复每次请求传输相同的头部字段;
3、多路复用–长连接的改进,不需要按序响应,解决了队头阻塞问题
4、主动推送功能的加入,服务器响应数据的时候可以附带响应依赖数据
长连接与短链接:
(1)短链接:建立 TCP 连接—> 发送请求—> 接收响应—> 关闭连接(每次获取一个资源,都要重新建立连接,关闭连接,效率低)
(2)长连接:
长连接:建立连接 —> 发送请求 —> 接收响应 —> … —> 关闭连接
长连接管线化传输:建立连接 —> 发送请求 —> 接收响应 —> 发送请求1 —> 发送请求2 —> 接收响应1 —> 接收响应2… —> 关闭连接
(二)请求头部
一个个的 键值对 ,对于请求的附加描述以及对正文的描述
请求头部:只会在请求中出现的头部字段,描述请求
Hosts:域名端口信息—>未指定端口默认 80
Referer:页面来源
正文头部:在请求与响应中都会出现,主要是对于正文的描述
Content-Length: n —> 正文长度
Content-Type: application/json;charset=UTF-8 —> 正文数据格式,决定了对方如何解析处理正文数据
响应头部:只会在响应中出现的头部字段,描述响应
Location:http://baidu.com —> 用于描述重定向到某一个网页
通用头部:在请求与响应中都会出现,属于对本次通信/连接的一些描述
Connection:keep-alive/close:用于描述当前的连接使用的是长连接还是短链接
(三)空行:间隔HTTP头部与正文
主要实现在HTTP协议解析时,先接收一个完整的HTTP协议头部,根据其中的Content-Length 确定正文长度,然后根据正文长度,取出指定长度的正文,则刚好能够完整的获取到一条HTTP请求
(四)正文:提交给服务器的数据
类型格式通过Content-Type描述得到数据的格式信息
响应格式
响应行、响应头部、空行、正文
(一)响应行
协议版本 状态码 状态码描述\r\n
例如: HTTP/1.1 200 OK\r\n
状态码:用于明确直接的向客户端表示本次请求的处理结果
1xx:继续请求或协议切换
101–协议切换
2xx:请求已经成功处理
200—OK成功处理
206—部分处理成功(区间内容处理成功)
3xx:请求进行了重定向(把一个请求重定向到其他链接。一个请求,要请求的资源被移到其他位置,但是想要保持原链接依旧有效)
301–> 永久重定向
302—> 临时重定向
303—>查看其它地址
304—>not modify ;
301,302,303 这种要跟Location响应头字段搭配使用,Location 字段用于指定重定向的新链接
4xx:表示客户端请求有错
400–>bad request
404–>请求不存在
414—>请求的 URL 过长,服务器无法进行处理
5xx:表示服务器错误
500–> internal error服务器内部错误
502–>bad gateway 代理服务器连接服务器失败
504–> gateway timeout 代理服务器连接服务器超时
详细的状态码解释:
添加链接描述
状态码描述:给程序员调试看的,一个对于状态码的文字描述信息
(二)响应头部: Connection 、Location…
(三)空行: 间隔头部与正文
(四)正文: 响应的数据内容
头部字段中的 Cookie (请求头) & Set-Cookie(响应头)
HTTP是一个简单的请求-响应协议,不论短连接/长连接,连接都不是一直连续的
cookie
cookie 是一种信息缓存机制,将一些信息保存至客户端主机上,等下一次请求服务器时候直接读取信息交给服务器,cookie这种缓存机制实现了HTTP的用户状态管理,但是不安全
session:会话
session 为客户端与服务端的通信建立一个会话,将会话重要内容保存起来在服务器上,通过 cookie 只需要传输 session_id 即可-------->在cookie基础上,避免了敏感信息的传输提高安全性
cookie vs session
cookie 将关键信息保存至客户端本地,每次通信前发送给服务器
session 将会话信息保存在服务器,通过 session_id 进行 cookie 传输,包含隐私性
cookie 篡改—> 解决方案:token
HTTPS 协议:对 HTTP 协议进行加密
加密:SSL/TLS 加密
加密:身份验证+加密传输
身份验证:采用的 CA 认证----电子认证服务
加密传输:对传输的数据进行加密(密钥协商)
(1)对称加密:数据的加密与解密使用的是相同的密钥; 加解密效率高,但是容易被劫持
(2)非对称加密:数据的加密与解密使用的密钥是不同的; 加解密效率低,但是安全性高
通过指定的算法(RSA)可以生成一对密钥(公钥 & 私钥),使用公钥进行数据加密,而加密后的数据只能使用私钥进行解密
(3)混合加密:
传输层
负责两端之间的数据传输 TCP / UDP
UDP 协议
用户数据报协议,无连接,不可靠,面向数据报传输
1、UDP 协议格式
2、UDP 协议特性:
(1)无连接:相较于TCP来说,通信前并不需要建立连接,只要知道对方地址信息就可以直接发送数据
(2)不可靠:传输过程中,不保证数据安全且有序的到达对端(没有丢包检测与重传机制)
(3)面向数据报传输:传输的数据有最大大小限制(64k-8,数据报头部占8字节),接收端向上交付数据的时候必须整条交付(UDP 数据在缓冲区中取出的时候:先取8字节报头,后取出长度 -8 的数据)
3、UDP 协议特性对于编程的影响:
(1)UDP 传输的报文有最大大小限制,因此程序员在使用 sendto 发送数据时,一次性不能发送太多数据,必须在应用层进行分包处理;
(2)UDP 不保证数据安全有序的到达对端,因此需要程序员在应用层进行包序管理,若有可靠要求则需要在应用层实现对应的丢包检测与重传机制;
(3)因为 UDP 要求必须整条交付,因此 recvfrom 接收数据时空间要足够大
4、UDP 支持局域网广播
TCP 协议
传输控制协议,面向连接、可靠传输、面向字节流传输
1、TCP 协议格式
16位源端端口 & 16位对端端口:描述通信两端进程
32位序号:告诉接收端,这条数据在整体数据中的排序,接收端根据序号进行排序
32位确认序号:向发送端进行确认回复,确认序号之前的数据都已经全部收到了
4位头部长度:以4字节为单位描述TCP报文头部长度,TCP报头最长60个字节,最小20字节; 解析过程:先取出20字节固定长度数据,然后根据头长取出选项数据长度-20
6位保留:暂未使用
6位标志位:
FIN:断开连接请求----FIN = 1 断开连接建立
SYN:连接建立请求— SYN=1 连接建立请求
RST:重置连接
PUSH:接收方可以取数据
ACK:确认应答回复
URG:紧急指针有效位------指向紧急数据
16位窗口大小:用于实现滑动窗口机制,进行流量控制(最长可以接收的数据–缓冲区最大容量)避免数据溢出而导致被丢弃
16位校验和:二进制反码求和算法,校验数据一致性
16位紧急指针:指向带外优先数据的结束位置
2、TCP 协议特性
面向连接:通信前先建立连接,确保双方具有数据收发能力
三次握手建立连接,四次挥手断开连接
1)三次握手建立连接:通信前要先建立连接,确保双方具有数据收发能力
Q1:为什么握手是三次,挥手是四次:
握手三次:两次不安全,四次没必要
(1)建立连接,是双方都要确保对方具有数据收发的能力,因此都需要进行 SYN;
(2)两次不安全:通信双方都需要确定对方是否具有数据收发能力,不能单方面决定;两次针对重传的多个SYN请求无法完美处理------> SYN有可能会延迟到达,与重发的SYN形成冲突(三次有状态要求); 防止恶意攻击,比如客户端发送SYN后直接退出
(3)四次没必要:没必要发送两次报文,在一次回复中将对应比特位置为1即可
Q2:三次握手失败,两端如何处理:
第一次握手失败:客户端发送的第一次握手请求丢了,客户端会重传SYN
第二次握手失败服务端回复ACK+SYN丢了,客户端会重传,服务端等待对方的ACK回复超时后,给客户端发送一个RST报文,然后释放资源
第三次握手失败服务器超时回复RST,然后释放资源
2)四次挥手断开连接:通信结束了会有一个断开连接过程,避免出现意外
FIN请求:只能表示不在给对方发送数据(不代表不接受数据)
CLOSE_WAIT:等待关闭,对方发送了FIN包,已经不再给自己发送数据,若上层这时候还在recv,则会读完缓冲区内数据后不在阻塞而是直接返回0
Q1:挥手为什么是四次?
FIN 请求只能表示主动关闭方不在发送数据,不代表不再接收数据,因此,被动关闭方收到 FIN 并进行确认后,还有可能会继续发送数据,等待上层不在发送数据了,也要关闭套接字了在会发送 FIN 包,因此挥手没有合并为三次
Q2:一台主机上发送了大量的 CLOSE_WAIT 状态连接,什么原因?
(1)只要收到了 FIN 请求并进行了确认回复的连接才会进入 CLOSE_WAIT 状态 ;
(2)一直处于 CLOSE_WAIT 而并未进行下一步状态,是因为上层没有进行关闭套接字操作,也就是没有发送 FIN 包,所有没有进行下一步;
(3)因此,原因就是代码中并未针对断开连接的套接字进行关闭处理
Q3:TIME_WAIT 状态有什么用,为什么不直接关闭套接字释放资源?
(1)TIME_WAIT 状态是主动关闭方在发送最后一次ACK后进入的状态;
(2)若没有TIME_WAIT,主动关闭方直接释放套接字资源,有可能新启动的套接字使用了与之前相同的地址信息;
(3)而上一次连接有可能最后一次ACK会丢失,一旦丢失 被动关闭方会重传FIN;
(4)从而导致上一次通信因为最后一次ACK丢失而遗留的问题(重传FIN)会对新连接造成影响;
因此不能直接释放资源,需要等待两个MSL时间,针对有可能存在的FIN重传问题进行处理,并保证上一次通信的所有数据都消失在网络中
MSL:保温最大生命周期(一个报文在网络中最大能存在的时间,默认 60s)
Q4:一台主机上出现了大量的TIME_WAIT状态连接,是什么原因,怎么处理?
(1)TIME_WAIT 是主动关闭方发送最后一次ACK后进入的状态,等待一段时间是为了处理有可能因为FIN丢失导致的FIN重传的处理
因此一台主机上出现大量的TIME_WAIT连接,是因为主机上大量的主动关闭方关闭了连接,常见于爬虫服务器;
(2)TIME_WAIT 等待时间是可配置的,可以将时间设置的更短;
(3)有个套接字选项,叫做地址重用 setsockopt()–让新连接可以绑定已经绑定了的端口信息;
3、TCP 连接管路中的保活机制
连接断开信息:recv 返回0,send 触发异常 SIGPIPE
在通信中,客户端与服务器若长时间无通信(默认7200s), 则TCP 服务器会自动向客户端发送保活探测心跳包,要求对方进行响应(默认每隔 75s),若连续多次没有受到响应(默认 9 次),则认为链接断开
TCP 心跳保活机制:
默认情况:TCP 通信,长时间(7200s)无数据往来则服务器每隔一段时间(75s)给客户发送保活探测数据包,要求客户端进行确认回复,若连续多次(9次)没有收到回复,则会断开连接
不是每个连接断开都会有四次挥手:
有:正常关机,关闭程序; 没有:机器断电,突然断网
这套心跳保活机制的默认时间都是可以配置的:通过套接字选项进行设置
4、可靠传输(TCP 如何实现可靠传输------> 很多特殊机制)
(1)面向连接—确保双方都具有数据收发能力
(2)丢包检测机制-确认应答机制:接收方要针对收到的每一条数据进行确认回复
(3)丢包重传机制-超时重传机制:等待确认回复超时则重传
(4)协议字段中的序号:进行包序管理,保证有序交付
(5)校验和字段:校验数据一致性,不一致则丢弃,要求重传
5、没有必要的性能损失处理机制:
1)滑动窗口机制:通过协议字段中的窗口大小字段实现
接收方每次接收到数据都会进行确认回复,再确认回复的时候就会计算自己接收缓冲区中剩余空间的大小,将这个数字放入窗口大小字段中给对方回复。发送方根据确认回复中的窗口大小字段确定自己最多发送多少数据
这就是TCP流量控制—避免因发送发发送数据过多导致接收方接收缓冲区溢出而导致丢包
MSS:最大数据段大小,一个TCP报文的最大数据大小,通信双方在三次握手阶段协商MSS大小,双方较小的值
MTU:链路层限制的最大传输单元,以太网默认1500字节
发送窗口:
(1)窗口后沿:记录了从哪个序号开始对数据进行编号发送----移动取决于是否收到了后沿数据的确认回复
(2)窗口前沿:记录了最多发送数据多少序号----移动取决于对方回复的窗口大小
(3)窗口前沿-窗口后沿 <= 接收方回复的窗口大小
确认回复-----表示确认序号之前的数据全部都已经收到了,若第一条数据丢了,但是收到了第二条数据,这时候是不能对第二条数据进行确认回复的
接收窗口:
(1)窗口后沿:记录要接收数据的起始序号----移动取决于收到起始序号的数据
(2)窗口前沿:记录当前接收数据的结束序号----移动取决于缓冲区剩余空间大小
(3)窗口前沿-窗口后沿 <= 缓冲区剩余大小
滑动窗口的三种重要协议:
(1)停等协议:发送方发送一条数据后,收到回复才会发送下一条数据--------适用于网络状况较差场景
(2)回退N步协议:滑动窗口机制决定了TCP数据传输可以管线化传输,可以连续发送多个报文,而在传输过程中若出现了丢包,回退N步协议,指的是从丢包的这个数据开始重新对数据进行传输-----------适用于网络状态一般的窗口
(3)选择重传协议:传输过程中哪个包丢了就对哪个包重传-------适用于网络较好场景
2)拥塞机制:
避免因为网络状况突变,网络拥塞而导致大量丢包的情况
3)快速重传协议:
在数据传输过程中,接收方接收数据时候并没有接收到起始接受序号的数据,而是接收到了后边的数据
也就是在第一条数据之前先收到了第二条数据,接收方不会对第二条数据进行确认回复,正常情况发送发等待确认回复,超时后进行第一条数据的超时重传-----------效率低
因此出现该情况后,接收方为提升效率会给发送发回复一个第一条数据的序号确认,并且在接受后续的数据过程中都会进行如此确认,而发送方连续收到三条第一条数据的确认回复则会对第一条数据进行重传-------避免因为网络延迟导致第一条数据没有及时接收到并未丢包,因此以三次作为判断标准
字节流传输:传输时,对数据以字节为单位进行编号进行传输,不限制传输大小
粘包问题:数据在缓冲区中堆积,将多条数据当作一条数据进行处理的过程
粘包产生的本质原因:数据之间缺乏边界管理
TCP粘包原因:TCP 在传输层并不管传输什么数据,只管从缓冲区中取合适大小的数据进行操作,没有边界管理
解决方案:在应用层程序员对数据进行边界管理
边界管理:明确一条数据从哪开始到哪结束
(1)特殊字符间隔:需要对数据中的特殊字符进行编码,避免歧义
(2)数据定长:数据固定长度,缺陷是需要以最大长度顶线(浪费多)
(3)数据采用 TLV 格式:在应用层头部中定义数据长度,先取头部,根据头部中数据长度决定去除多少数据------典型做法:HTTP、UDP
UDP 根本没有粘包问题,因为UDP面向数据报传输方式,一次最多交付一条数据(UDP本身就有数据的边界管理),UDP 的 sendto 接口发送数据,将数据放到发送缓冲区之后会立刻封装头部进行发送
连接断开在程序中的反馈:RECV 接收数据返回 0;send 发送数据会触发 SIGPIPE 异常
文章评论