网络相关-TCP/HTTP/HTTPS

网络传输模型

img

TCP/IP

数据包

每个分层中, 都会对所发送的数据附加一个首部, 在这个首部中包含了该层必要的信息, 如发送的目标地址以及协议相关信息. 通常, 为协议提供的信息为包首部, 所要发送的内容为数据. 在下一层的角度看, 从上一层收到的包全部都被认为是本层的数据

网络中传输的数据包由两部分组成:一部分是协议所要用到的首部, 另一部分是上一层传过来的数据. 首部的结构由协议的具体规范详细定义. 在数据包的首部, 明确标明了协议应该如何读取数据. 反过来说, 看到首部, 也就能够了解该协议必要的信息以及所要处理的数据

img

数据处理流程

img

TCP 头部结构

源端口和目的端口: 各占两个字节, 分别写入源端口号和目的端口号.
序号 : 占4个字节;用于对字节流进行编号, 例如序号为 301, 表示第一个字节的编号为 301, 如果携带的数据长度为 100 字节, 那么下一个报文段的序号应为 401.
确认号 : 占4个字节;期望收到的下一个报文段的序号. 例如 B 正确收到 A 发送来的一个报文段, 序号为 501, 携带的数据长度为 200 字节, 因此 B 期望下一个报文段的序号为 701, B 发送给 A 的确认报文段中确认号就为 701.
数据偏移 : 占4位;指的是数据部分距离报文段起始处的偏移量, 实际上指的是首部的长度.
确认 ACK : 当 ACK=1 时确认号字段有效, 否则无效. TCP 规定, 在连接建立后所有传送的报文段都必须把 ACK 置 1.
同步 SYN :在连接建立时用来同步序号. 当 SYN=1, ACK=0 时表示这是一个连接请求报文段. 若对方同意建立连接, 则响应报文中 SYN=1, ACK=1.
终止 FIN : 用来释放一个连接, 当 FIN=1 时, 表示此报文段的发送方的数据已发送完毕, 并要求释放连接.
窗口 : 占2字节;窗口值作为接收方让发送方设置其发送窗口的依据. 之所以要有这个限制, 是因为接收方的数据缓存空间是有限的.
检验和: 占2个字节;检验和字段检验的范围包括首部和数据这两个部分. 在计算检验和时, 在TCP报文段的前面加上12字节的伪首部.
套接字: TCP连接的端点叫做套接字或插口. 端口号拼接到IP地址即构成了套接字.

img

UDP 头部结构

源端口: 源端口号, 在需要给对方回信时使用. 不需要是可全用0.
目的端口号: 这在终点交付报文时必须使用.
长度: 用户数据报UDP的长度, 最小为8(仅首部).
校验和: 用于校验用户数据报在传输过程是否出错, 出错则丢弃该报文.

udp

TCP 和 UDP 区别

TCP: 面向连接;每一个TCP连接只能是点对点的(一对一);提供可靠交付服务;提供全双工通信;面向字节流. 应用程序和TCP的交互是一次一个数据块(大小不等), 但TCP把应用程序看成是一连串的无结构的字节流. TCP有一个缓冲, 当应该程序传送的数据块太长, TCP就可以把它划分短一些再传送

UDP: 无连接;尽最大努力的交付;面向报文;无拥塞控制;支持一对一、一对多、多对一、多对多的交互通信;首部开销小(只有四个字段:源端口、目的端口、长度、检验和). UDP是面向报文的传输方式是应用层交给UDP多长的报文, UDP发送多长的报文, 即一次发送一个报文. 因此, 应用程序必须选择合适大小的报文

img

三次握手

为什么要三次挥手: 为了防止已失效的连接请求报文段突然又传送到了服务端, 因而产生错误

img

四次挥手

为什么需要四次挥手: 客户端发送了 FIN 连接释放报文之后, 服务器收到了这个报文, 就进入了 CLOSE-WAIT 状态. 这个状态是为了让服务器端发送还未传送完毕的数据, 传送完毕之后, 服务器会发送 FIN 连接释放报文

img

为什么等待 2MSL

MSL(Maximum Segment Lifetime ):报文段最大生存时间, 它是任何报文段被丢弃前在网络内的最长时间

保证TCP协议的全双工连接能够可靠关闭: 如果主机1直接 关闭, 由于IP协议的不可靠性或者其他网络原因, 导致主机2没有收到主机1最后回复的 ACK. 那么主机2就会在超时之后继续发送 FIN, 此时由于主机1已经关闭, 就找不到与重发的 FIN 对应的连接. 所以, 主机1 不是直接进入 关闭, 而是TIME_WAIT 状态. 当再次收到 FIN 的时候, 能够保证对方收到 ACK , 最后正确关闭连接

保证这次连接的重复数据从网络中消失: 如果主机1直接 关闭, 然后又再向主机 2 发起一个新连接, 我们不能保证这个新连接与刚才关闭的连接端口是不同的. 也就是说有可能新连接和老连接的端口号是相同的. 一般来说不会发生什么问题, 但还是有特殊情况出现;假设新连接和已经关闭的老连接端口号是一样的, 如果前一次连接的某些数据仍然滞留在网络中( Lost Duplicate ), 那些延迟数据在建立新连接之后才到达主机2, 由于新连接和老连接的端口号是一样的, TCP 协议就认为哪个延迟的数据时属于新连接的, 这样就和真正的新连接的数据包发生混淆了. 所以TCP连接要在 TIME_WAIT 状态等待两倍 MSL , 保证本次连接的所有数据都从网络中消失

通过序列号和确认号保证可靠性和顺序性传输

下图展示序列号和确认号如果保证可靠性和顺序性传输

img

重传机制

RTT(Round Trip Time)

RTT(Round Trip Time) 就是数据从网络一端传送到另一端所需的时间, 也就是包的往返时间

RTT的测量:

  1. TCP Timestamp选项:在TCP选项中添加时间戳选项, 发送数据包的时候记录下时间, 收到数据包的时候计算当前时间和时间戳的差值就能得到RTT. 这个方法简单并且准确, 但是需要发送段和接收端都支持这个选项
  2. 重传队列中数据包的TCP控制块:每个数据包第一次发送出去后都会放到重传队列中, 数据包中的TCP控制块包含着一个变量, tcp_skb_cb->when, 记录了该数据包的第一次发送时间. 如果没有时间戳选项, 那么RTT就等于当前时间和when的差值

img

RTO(Retransmission Time Out)

超时重传时间 RTO 的值应该略大于报文往返 RTT 的值, 理由:

  1. 当超时时间 RTO 较大时, 重发就慢, 丢了老半天才重发, 没有效率, 性能差
  2. 当超时时间 RTO 较小时, 会导致可能并没有丢就重发, 于是重发的就快, 会增加网络拥塞, 导致更多的超时, 更多的超时导致更多的重发

具体的超时重传时间 RTO 根据不同的拥塞算法, 算法不同

超时重传

重传机制的其中一个方式, 就是在发送数据时, 设定一个定时器, 当超过指定的时间后, 没有收到对方的 ACK 确认应答报文, 就会重发该数据, 也就是我们常说的超时重传

TCP 会在以下两种情况发生超时重传:

  1. 数据包丢失
  2. 确认应答丢失

img

快速重传

快速重传不以时间为驱动, 而是以数据驱动重传

快速重传机制只解决了一个问题, 就是超时时间的问题, 但是它依然面临着另外一个问题. 就是重传的时候, 是重传之前的一个, 还是重传所有的问题. 根据不同的算法, 机制不同

img

SACK 快速重传

SACK(Selective Acknowledgment): 选择性确认. 这种方式需要在 TCP 头部「选项」字段里加一个 SACK 的东西, 它可以将缓存的地图发送给发送方, 这样发送方就可以知道哪些数据收到了, 哪些数据没收到, 知道了这些信息, 就可以只重传丢失的数据

需要发送方和接收方都支持 SACK

img

D-SACK 快速重传

D-SACK 又称(Duplicate SACK) , 其主要使用了 SACK 来告诉「发送方」有哪些数据被重复接收了

DSACK 这个机制是在 SACK 的基础上, 额外携带信息, 告知发送方有哪些数据包自己重复接收了. DSACK 的目的是帮助发送方判断, 是否发生了包失序、ACK 丢失、包重复或伪重传. 让 TCP 可以更好的做网络流控

好处:

  1. 可以让「发送方」知道, 是发出去的包丢了, 还是接收方回应的 ACK 包丢了
  2. 可以知道是不是「发送方」的数据包被网络延迟了
  3. 可以知道网络中是不是把「发送方」的数据包给复制了

img

滑动窗口

以段为单位发送数据

MSS(Maximum Segment Size): 最大报文长度

在建立 TCP 连接的同时, 也可以确定发送数据包的单位, 我们也可以称其为“最大消息长度”(MSS). 最理想的情况是, 最大消息长度正好是 IP 中不会被分片处理的最大数据长度

TCP 在传送大量数据时, 是以 MSS 的大小将数据进行分割发送. 进行重发时也是以 MSS 为单位

MSS 在三次握手的时候, 在两端主机之间被计算得出. 两端的主机在发出建立连接的请求时, 会在 TCP 首部中写入 MSS 选项, 告诉对方自己的接口能够适应的 MSS 的大小. 然后会在两者之间选择一个较小的值投入使

利用窗口控制提高速度

确认应答不再是以每个分段, 而是以更大的单位进行确认, 转发时间将会被大幅地缩短. 也就是说, 发送端主机, 在发送了一个段以后不必要一直等待确认应答, 而是继续发送

img

滑动窗口控制

TCP 头里有一个字段叫 Window, 也就是窗口大小

这个字段是接收端告诉发送端自己还有多少缓冲区可以接收数据. 于是发送端就可以根据这个接收端的处理能力来发送数据, 而不会导致接收端处理不过来. 通常窗口的大小是由接收方的窗口大小来决定的. 发送方发送的数据大小不能超过接收方的窗口大小, 否则接收方就无法正常接收到数据

swnd: 发送窗口
rwnd: 接受窗口
cwnd:: 拥塞窗口

发送窗口=Min(拥塞窗口, 接受窗口)

img

img

流量控制

流量控制是为了解决发送方和接收方速度不同而导致的数据丢失问题,当发送方发送的太快,接收方来不及接受就会导致数据丢失,流量控制用滑动窗口的形式解决问题

假设接收方的主机B进行了三次流量控制. 第一次把窗口设置为rwind=300, 第二次减小到rwind=100最后减到rwind=0, 即不允许发送方再发送过数据了. 这种使发送方暂停发送的状态将持续到主机B重新发出一个新的窗口值为止.

如果主机 B 发送的新窗口值丢包, 就会导致主机 A 等到主机 B 发送新窗口, 主机 B 等待主机 A 发送报文. 导致死锁. 为了解决这个问题, TCP 为每个连接设有一个持续定时器, 只要TCP连接的一方收到对方的零窗口通知, 就启动持续计时器, 若持续计时器设置的时间到期, 就发送一个零窗口探测报文段(仅携带1字节的数据), 而对方就在确认这个探测报文段时给出了现在的窗口值

拥塞控制

拥塞控制是为了解决过多的数据注入到网络,导致网络奔溃,超过负荷.当发送方发送数据大量的数据会注入到网络,如果没有限制,网络就会超负荷变卡,拥塞控制的用的是拥塞窗口解决的问题的

慢启动

当发送方每收到一个 ACK, 拥塞窗口 cwnd 的大小就会加 1

  1. 连接建立完成后, 一开始初始化 cwnd = 1, 表示可以传一个 MSS 大小的数据
  2. 当收到一个 ACK 确认应答后, cwnd 增加 1, 于是一次能够发送 2 个
  3. 当收到 2 个的 ACK 确认应答后, cwnd 增加 2, 于是就可以比之前多发2 个, 所以这一次能够发送 4 个
  4. 当这 4 个的 ACK 确认到来的时候, 每个确认 cwnd 增加 1, 4 个确认 cwnd 增加 4, 于是就可以比之前多发 4 个, 所以这一次能够发送 8 个

ssthresh(slow start threshold): 慢启动门限

img

拥塞避免

当拥塞窗口 cwnd 「超过」慢启动门限 ssthresh 就会进入拥塞避免算法. 一般来说 ssthresh 的大小是 65535 字节.

进入拥塞避免算法后, 它的规则是:每当收到一个 ACK 时, cwnd 增加 1/cwnd

拥塞避免算法就是将原本慢启动算法的指数增长变成了线性增长, 还是增长阶段, 但是增长速度缓慢了一些

img

拥塞发生(快重传, 超时重传)

当触发了重传机制, 也就进入了拥塞发生算法. ssthresh 设为 cwnd/2, cwnd 重置为 1

img

快恢复

快速重传和快速恢复算法一般同时使用, 快速恢复算法是认为, 你还能收到 3 个重复 ACK 说明网络也不那么糟糕, 所以没有必要像 RTO 超时那么强烈

  1. 拥塞窗口 cwnd = ssthresh + 3 ( 3 的意思是确认有 3 个数据包被收到了)
  2. 重传丢失的数据包
  3. 如果再收到重复的 ACK, 那么 cwnd 增加 1
  4. 如果收到新数据的 ACK 后, 把 cwnd 设置为第一步中的 ssthresh 的值, 原因是该 ACK 确认了新的数据, 说明从 duplicated ACK 时的数据都已收到, 该恢复过程已经结束, 可以回到恢复之前的状态了, 也即再次进入拥塞避免状态

img

Nagle

若发送应用进程把要发送的数据逐个字节地送到TCP的发送缓存, 则发送方就把第一个数据字节先发送出去, 把后面的数据字节都缓存起来. 当发送方收到对第一个数据字符的确认后, 再把发送缓存中的所有数据组装成一个报文段发送出去, 同时继续对后面的数据先进行写入缓存. 只有收到对签名一个报文段的确认后才继续发送下一段报文

TCP/IP希望每次都能够以MSS尺寸的数据块来发送数据
Nagle算法就是为了尽可能发送大块数据, 避免网络中充斥着许多小数据块(停止-等待)

  1. 如果包长度达到MSS, 则允许发送
  2. 如果该包含有FIN, 则允许发送
  3. 设置了TCP_NODELAY选项, 则允许发送
  4. 未设置TCP_CORK选项时, 若所有发出去的小数据包(包长度小于MSS)均被确认, 则允许发送
  5. 上述条件都未满足, 但发生了超时(一般为200ms), 则立即发送

作用: 提升吞吐量, 降实时性, 避免网络拥塞

如何关闭: TCP_NODELAY

Nagle 遇到 Delayed ACK

炸裂

HTTP

img

工作流程

  1. 客户机与服务器建立TCP连接. 只要单击某个超级链接/输入网址/提交表单等
  2. 建立连接后, 客户机发送http请求给服务器
  3. 服务器接到请求后, 响应信息
  4. 客户端接收服务器所返回的信息, 然后客户机与服务器断开TCP连接

HTTP 1.1

  1. 增加长连接 Connection: keep-alive
  2. 支持并发连接(最多 6-8)
  3. 支持管道(pipeling)
    1. pipeling 要求按序, 虽然支持一次发送多次请求, 但是如果前者耗时很长, 后者仍无法响应(队头阻塞)

HTTP 2.0

  1. 二进制协议(帧)
  2. 多路复用
  3. 头部信息压缩
  4. 服务端主动推送
  5. 支持数据流

多路复用多个请求(同一个域名)使用同一个 tcp, 如果出现丢包情况, 则性能不如 1.1. 因为一旦丢包, 则会出发重传机制, 阻塞整个 tcp 连接

HTTPS

  1. 三次握手(2RTT)
  2. ssl/tls 证书流程(tls 1.3 1RTT)
  3. 数据传输
  4. 四次挥手

img

HTTP 通信过程

对称加密

加密和解密都是使用同一个密钥, 常见的对称加密算法有 DES、3DES 和 AES

优点: 算法公开, 计算量小, 加密速度快, 加密效率高
缺点: 交易双方需要使用相同的密钥, 也就无法避免密钥的传输, 而密钥在传输过程中无法保证不被截获, 因此对称加密的安全性得不到保证

img

非对称加密

加密和解密需要使用两个不同的密钥: 私钥和公钥

公钥与私钥是一对, 如果用公钥对数据进行加密, 只有用对应的私钥才能解密. 如果用私钥对数据进行加密, 那么只有用对应的公钥才能解密

优点: 算法公开,加密和解密使用不同的钥匙,私钥不需要通过网络进行传输,安全性很高
缺点: 计算量比较大,加密和解密速度相比对称加密慢很多

img

交互流程
  1. 三次握手建立连接(会将证书公钥等返回 2RTT)
  2. 生成随机码加密, 使用公钥加密(当做对称加密的密钥), 发送给服务端
  3. 服务端接收后使用私钥解密, 得到对称加密的密钥. 通过对称加密的密钥对传输数据加密返回
  4. 使用之前生成的对称加密密钥解密, 后续通过此对称加密密钥传输数据(1RTT)

img

QUIC

基于 UDP 实现的传输层协议

img

数据包

Header是明文传输,包括Flags是标志位,Connection ID是连接ID,可用于连接迁移,QUIC Version是QUIC的版本号,Packet Number是包序号,用于保证可靠传输;Data部分是密文传输,是一些数据帧,有很多数据帧类型:Stream、ACK、Padding、Blocked等,其中Stream帧传输应用数据

img

img

通信流程

HTTPS 连接仅需 1RTT

img

可靠传输

可靠传输必须满足两个条件

  1. 数据完整性:发送端发出的数据包,接收端都能收到
  2. 数据有序性:接收端能按序组装数据包,解码得到原始数据

基于包号PKN和确认应答SACK的丢包重传机制

PKN是单调递增的,即使是重传,PKN也和之前的不一样。那么接收端怎么保证数据的有序性呢?
通过添加数据包在原始数据中的偏移量offset,接收端根据offset字段对异步到达的数据包进行排序

img

img

无对头阻塞

给每个流都分配一个滑动窗口. 虽然单条连接上无队头阻塞,但是单条流仍然存在队头阻塞

img

流量控制

和 TCP 一致通过滑动窗口控制

TCP不同的是,QUIC的滑动窗口分为Connect和Stream两种级别

  1. Connnect流量控制:规定了所有数据流的总窗口大小
  2. Stream流量控制:规定了每个流的窗口大小

因为QUIC中每个连接上可以发送多个请求,每个请求对应一条流,每个流有自己的滑动窗口,整个连接也有一个滑动窗口,其大小是所有流的可用窗口之和

img

自定义拥塞控制

基于应用层的拥塞协议. 例Cubic, BBR, Reno

连接迁移

从 wifi 切换到数据网络

TCP: 由于 ip 切换, 连接则会切断重连
quic: 使用 connectionId 来标识连接, 无需切断重连

img

前向纠错(FEC)

弱网丢包环境下,动态的增加一些FEC数据包,可以减少重传次数,提升传输效率. 每发送一组数据,包括若干个数据包后,并对这些数据包依次做异或运算,最后的结果作为一个FEC包再发送出去。接收方收到一组数据后,根据数据包和FEC包即可以进行校验和纠错

缺点: 对抗网络延迟上作用不大,还浪费带宽

img

引用

30张图解: TCP 重传、滑动窗口、流量控制、拥塞控制发愁

终于有人能把TCP/IP 协议讲的明明白白了

菜鸟日记


网络相关-TCP/HTTP/HTTPS
https://gallrax.github.io/2023/04/11/网络相关/
作者
Gallrax
发布于
2023年4月11日
许可协议