### 传输层有两个协议 - TCP Transmission Control Protocol 传输控制协议 - UDP User Datagram Protocol 用户数据报协议 image ### UDP - 无连接,减少了建立和释放链接的开销 - 尽最大能力交付,不保证可靠传输 - 首部较小,UDP首部只有8个字节 ![image](https://user-images.githubusercontent.com/39154923/137895070-81ec320b-4196-4766-9438-2f8166e7712c.png) - UDP长度:首部的长度 + 数据部分的长度 - UDP检验和:计算的是伪首部(12字节) + 首部(8字节) + 数据 - 伪首部:仅在计算检验和时起作用,并不会传递给网络层 ![image](https://user-images.githubusercontent.com/39154923/137895425-44be7955-9425-4853-aefa-390eebe621e1.png) - UDP:客户端源端口时临时开启的随机端口 ### 伪首部 - 源IP 4字节 - 目标IP 4字节 - 零填充 + 协议 + 长度(首部 + 数据部分) 4字节 - TCP与UDP伪首部是一样的 - 仅在计算检验和时起作用 ### TCP ![image](https://user-images.githubusercontent.com/39154923/138079676-0dfb6af5-a696-465e-9602-5be81e29e9a1.png) - TCP首部的空间至少是20字节,最大60字节 - 和UDP一样 也有12个字节的伪首部,不会传递到网络层 - 数据偏移占4位,取值范围 0x0101~0x1111,乘4代表首部长度,最小值是5,最大值是15 ### TCP要点 - 可靠传输 - 流量控制 - 拥塞控制 - 连接管理 ### 数据长度 - UDP首部用16位记录整个UDP数据加首部的长度 - TCP用4位标记了TCP报文首部长度,并没有记录数据长度 - 传输层的数据长度 = 网络层的数据长度 - 网络层的首部长度 - 传输层的首部长度 ### TCP flag含义 - URG:Urgent,紧急字段,为1时,表示当前报文段中有紧急数据,需要优先传输,尽快传送 - ACK:Acknowledgment 确认字段,当ack为1时,首部中的确认号字段才有效 - PSH:Push 交互式网络 - RST:Reset,为1时,表明链接中出现严重差错,必须释放连接,然后重新创建连接 - SYN:Synchronization - SYN = 1,ACK = 0时,表明这是一个建立连接的请求 - SYN = 1,ACK = 1时,表明对方同意建立连接 - FIN:Finish,为1时,表明数据已经发送完毕,要求释放连接 ### 序号 - 4个字节 - 传输过程中,每一个字节都会有一个编号 - 建立连接后,序号代表:这一次传给对方的TCP数据部分的第一个字节的编号 ### 确认号 - 4个字节 - 建立连接后,确认号代表:期望对方下一次传过来的TCP数据部分的第一个字节的编号 ### TCP 可靠传输 - 三次握手 - 四次挥手 - ARQ协议(Automatic Repeat Request) 自动重传协议,超时重传 + 每个包重试次数过多会发送reset报文,重新创建连接 - 滑动窗口协议:批量发送,批量确认,从确认的报文的下一个开始重新发送 - SACK(selective acknowledgment),选择确认,放在TCP首部的选项部分 - 拥塞控制 #### SACK 选择确认 - 放在TCP首部的选项部分 - kind 1字节,值为5代表是sack - length 1字节,代表sack部分的长度占用多少字节 - left range 左边界 4字节 - right range 右边界 4字节 - 每个选项部分最多携带4组边界值 - 选项部分最长40字节 - 4 * 8 + 2 = 34 ### TCP 流量控制 - 不进行流量控制接收方已经无法接受了,发送方还在发送,造成浪费 - `点对点`的控制发送方的发送速率 - 通过读取接收方的窗口大小,来控制发送方发送数据的多少 - 发送方的窗口 `<=` 接收方的窗口大小 - 接收方窗口为0,发送方停止发送,如果还有报文要发送,就定时询问接收方的窗口大小 ### TCP 拥塞控制 - 防止过多的数据注入到网络中 - 防止链路过载或网络中传输的硬件过载 #### 方法 - 慢开始:cwnd 指数级增长 - 拥塞避免:到达慢开始阈值后,cwdn线性增长 - 快速重传:连续收到同一个报文的3次确认后,立即重新发送下一个报文 - 快速恢复:遇到网络拥塞,然后cwnd的起始值变为慢开始阈值的一半,线性增长 > - MSS: Maximum Segment Size 每个数据段的数据最大大小 > - cwnd congestion window 拥塞窗口 > - rwnd receive window 接收窗口 > - swnd send window 发送窗口 > - swnd = min(cwnd, rwnd) > - slow start threshold 慢开始阈值,到达阈值后,cwdn 线性增长 ### TCP 连接管理 - 连接时三次握手 - 断开连接时四次挥手 #### TCP 建立连接 三次握手 - closed 客户端处于关闭状态 - listen server处于监听状态,等待客户端连接 - syn-rcvd server端收到了客户端发送的建立链接报文后的状态 - syn-sent client端发送了建立连接报文后的状态 - established 连接建立状态 - client收到了server返回的确认建立连接报文的状态 - server端收到了client返回的对建立连接报文进行确认的报文后的状态 ![](https://blog-heysq-1255479807.cos.ap-beijing.myqcloud.com/blog/wiki/http/tcp_handshake.png) - 前两次建立连接的特点 - 数据部分长度都为0 - SYN都设置为1 - 首部长度为32字节(20字节首部 + 12字节选线部分) - 会交换MSS,是否支持SACK,和窗口大小 ##### 为什么不采用2次握手 - 两次握手,服务端收到客户端的请求就建立连接,容易造成浪费资源 - 客户端发送的链接建立请求因为网络波动,导致超时送达,此时链接已经释放 - 如果采用两次握手,服务端会对这个延迟的报文进行确认建立连接,但是客户端并无链接意愿,就会造成服务端连接浪费 ##### 第3次握手失败了,怎么处理 - 因为网络问题,导致server并没有收到client端的3次握手 - 服务端超时时间内,重新发送SYN + ACK确认包 - 如果发送多次确认包都没有收到回复,则会发送RST包,强制关闭连接 #### TCP 断开连接 四次挥手 - `fin_wait1` 主动关闭链接,并且向对方发送了关闭链接报文 - `fin_wait2` 收到对方发送的ACK确认报文,然后等待对方发送关闭连接报文 - `close_wait` 收到对方发送的关闭链接报文,并向对方回复了ACK确认报文 - 判断对方自己是否还有数据要发给对方,有就继续发送数据 - 没有就发送FIN报文表示自己也想关闭连接 - `closing` 双方同时收到了对方发送的FIN报文 - `last_ack` 被动关闭的一方,在发送完FIN报文后,等待另一方确认 - `time_wait` 收到了对方的FIN报文,并回复了ACK,等2MSL时间后就自动进入`closed`状态 - 如果在`fin_wait1`状态据收到了对方的FIN和ACK一起的报文,就可以直接进入到`time_wait`状态 - `closed` 关闭状态 ![](https://blog-heysq-1255479807.cos.ap-beijing.myqcloud.com/blog/wiki/http/tcp_wave.jpg) #### TCP 断开连接细节 - 连接双方任意一方都可以主动关闭连接 - 全双工通信,双向关闭连接 - 主动关闭一方发送对另一方的FIN报文确认的ACK后,需要等待2MSL - MSL(Maximum Segment Lifetime)TCP报文在internet中最大生存时间 #### 一方发送ACK后,断开连接 - 如果网络波动,造成另一方没有收到ACK,就会重复发送FIN - 忽略FIN,造成另一方资源浪费 - 接收FIN,造成端口相同的新连接在收到报文后响应关闭连接