Loading... # 运输层(二) ## TCP ### TCP连接 特点: * 点对点:单个发送方和接收方 * 可靠、有序字节流 * 流水线 * 全双工数据(full duplex data):双向数据通过同一个连接 MSS:Maximum segment size,最大报文段长度(传输层能承载的应用层最大数据长度,不包括传输层的头部) * 面向连接: * 流量控制 ### TCP报文结构 首部字段+数据字段 <img src="http://xherlock.top/usr/uploads/2022/05/937204793.png" alt="shadow3" style="zoom: 67%;" style=""> 首部: * 源端口号和目的端口号:用于多路复用和分解 * 序号:32bit * 确认号:32bit,和序号一起用于实现可靠数据传输服务 * 首部长度:4bit,指示了以32bit的字为单位的TCP首部长度(通常选项字段为空,TCP首部典型长度位20字节,每行4字节) * 标志字段 * URG:指示报文段力存在着被发送端的上层实体置为“紧急”的数据 * ACK:指示确认字段中的值有效,即该报文段包括一个对已被成功接收报文段的确认 * PSH:指示接收方将数据交给上层 * RST、SYN、FIN:用于连接建立和拆除 * 接收窗口:16bit,用于流量控制(接收方愿意接收的字节数量) * 检验和:同UDP * 紧急数据指针(不怎么用) * 选项:可选、变长,用于发送方和接收方协商MSS或者在高速网络环境下用作窗口调节因子使用 * 应用数据:MSS长 **序号和确认号** TCP把数据看成一个无结构的、有序的**字节流**,而不是报文段序列。因此一个报文段的序号时该报文段**首个字节数据的编号** eg: ![image-20220428095806510.png](http://xherlock.top/usr/uploads/2022/05/3731480836.png) 1st报文段seq为0,2nd报文段seq为1000 --- ACK是接收方期待收到的字节数据的序列号 eg: 主机A接收到了来自B的编号为0~535的所有字节,将会发送ACK为536的报文段 TCP只确认字节流中至第一个丢失字节为止的字节,即提供累计确认 eg: 主机A接收到了来自B的编号为0\~535、900\~1000的报文段,A仍等待字节536,将会发送ACK为536的报文段 如果TCP收到失序报文,交给编程人员自己处理 1. 接收方立即丢弃失序报文 2. 接收方保留失序的字节,并等待缺少的字节以填补间隔(对网络带宽更有效,实践中常用) --- 一条TCP连接的双方均可随机选择初始序号:减少先前终止连接的报文段被误认为是新建连接的有效报文段的可能性(碰巧使用相同端口号) ![image-20220428104033306.png](http://xherlock.top/usr/uploads/2022/05/124427997.png) ### 往返时间的估计与超时 报文段的样本RTT(**SampleRTT**):从某报文段被发出到对该报文段的确认被收到之间的时间 为了估计出更加典型的RTT,采用对SampleRTT取平均的办法,并维持该均值(**EstimatedRTT**) **EstimatedRTT = (1 - α) * EstimatedRTT + α * SampleRTT** (推荐值α=0.125,这是一个加权平均值,加权平均对最近的样本赋予的权值要大于旧样本赋予的权值) 除了测量RTT外,还需要测量RTT的变化,定义RTT偏差(DevRTT) **DevRTT= (1 - β) * DevRTT+ β * |SampleRTT - EstimatedRTT |** (推荐β=0.25,可以看出SampleRTT值波动越大,DevRTT值就会很大 ) --- 设置超时间隔必须大于连接往返时间(RTT) * 过短:过早超时,导致不必要的重传 * 过长:不能对快速重传丢失的报文段,造成数据传输时延增大 故应设置超时间隔为EstimatedRTT加上一定余量(safety margin):**TimeoutInterval = EstimatedRTT+4*DevRTT** ### 可靠数据传输 * 流水线报文段 * 累计确认 * 单个重传定时器 重传触发: * 超时 * 冗余ACK 简化后的发送方三个重要事件; 1. 收到APP发送的数据: 2. 超时:重传导致超时事件的报文;重启计时器 3. 收到ACK:将ACK的值和变量SendBase(最早未被确认的字节的序号)进行比较,由于采用累计确认,ACK的值确认了在它之前的所有字节都已收到;如果有仍未被确认的报文段,TCP重启计时器 1、3两个事件**TimeoutInterval = EstimatedRTT+4*DevRTT**,2超时事件发生时,TimeoutInterval加倍(提供了一种有限形式的拥塞控制机制) ![image-20220501092803509.png](http://xherlock.top/usr/uploads/2022/05/1862198831.png) **发送成功,未收到ACK导致超时重传,重传的数据包冗余丢弃,返回ACK报文** <img src="http://xherlock.top/usr/uploads/2022/05/816352154.png" alt="5706260DFF1106A2EBCC911BFDD72257" style="zoom:50%;" style=""> **连续发回的两个ACK数据包均超时,仅重传最小序列号未被确认的数据包并重启计时器**,只要第二个报文段的ACK在新的超时发生以前到达,第二个报文段将不会被重传 <img src="http://xherlock.top/usr/uploads/2022/05/1459328905.png" alt="BB91B7E61113095760F7ECED4C008D0E" style="zoom:50%;" style=""> **若发送的两个报文段均收到,返回的第一个ACK丢失,第二个ACK在超时前收到,则确定第二个ACK前的报文段都收到了,不再重传** ![image-20220501095338219.png](http://xherlock.top/usr/uploads/2022/05/2613184015.png) **TCP接收方的ACK生成策略** ![image-20220501095733728.png](http://xherlock.top/usr/uploads/2022/05/3874172195.png) **TCP快速重传** * 超时周期可能相对较长,导致端到端时延 * 通过冗余ACK检测丢包(丢包后会不断收到ACK):因此采用收到3个冗余ACK就确认该报文段,**快速重传**,不必等待计时器 ![image-20220501100542115.png](http://xherlock.top/usr/uploads/2022/05/2058943187.png) ### 流量控制 发送方发送的太多、太快会使接受方数据缓存溢出,因此提供流量控制 ![image-20220501103300923.png](http://xherlock.top/usr/uploads/2022/05/1583991098.png) LastByteRead:应用层从缓存中读取的最新一个字节的编号 LastByteRcvd:到达接收缓存最新字节数据的编号 TCP不允许已分配的缓存溢出:**LastByteRcvd - LastByteRead ≤ RcvBuffer** 接受窗口(rwnd,缓存可用空间)rwnd = RcvBuffer - [LastByteRcvd - LastByteRead] **接收方将当前的rwnd值放入发给发送方的报文段接收窗口字段中** 发送方追踪LastByteSent和LastByteAcked,保证**LastByteSent - LastByteAcked ≤ rwnd** ### 连接管理 #### 建立TCP连接 1. 客户端向服务器发送不含应用层数据的TCP报文段,报文段的首部标志位SYN置1(**SYN报文段**),并随即选取初始序号(client_isn) 2. 服务器接收到SYN报文段,为TCP连接分配缓存和变量,同时确定自己的初始序号(server_isn),返回不含数据的**SYNACK报文段** 3. 客户收到SYNACK报文段后,也给连接分配缓存和变量,并发送报文段(可能含有数据,因此可以是**第一个HTTP请求**),**seq = client_isn + 1**,由于连接已建立,SYN比特置0 ——**3次握手** ![image-20220501110119564.png](http://xherlock.top/usr/uploads/2022/05/3357387472.png) #### 关闭TCP连接 1. 客户端发送首部标志位FIN置1的的TCP报文段给服务器 2. 服务器接收FIN报文段,发回确认报文段,过一会后就发送自己的终止报文段(FIN置1) 3. 客户端接收服务器的FIN报文段,也返回ACK 4. 服务器接收到ACK后关闭连接 ![image-20220501113237916.png](http://xherlock.top/usr/uploads/2022/05/491065332.png) **Timed Wait**:服务器如果在timeout内未收到客户端的ACK,重新发送FIN;客户端在Timed Wait内再次收到FIN,重发ACK并重新进入Timed Wait状态,确保服务器能进入到关闭状态 **客户端连接状态** ![image-20220501113103133.png](http://xherlock.top/usr/uploads/2022/05/727814179.png) FIN_WAIT_1:等待服务器的ACK FIN_WAIT_2:等待服务器的FIN TIME_WAIT:等待可能到达的FIN(客户端发送的ACK可能丢失) **服务器连接状态** ![image-20220501113508813.png](http://xherlock.top/usr/uploads/2022/05/11403184.png) **整体** ![image-20220501113632474.png](http://xherlock.top/usr/uploads/2022/05/3144387656.png) 当一台主机接受了一个SYN分组,但端口号或目标IP地址不符合当前所有运行的套接字,如果是TCP分组,发送一个RST(重置,标志位置1)报文段;如果是UDP分组,发送一个ICMP数据报 最后修改:2022 年 05 月 01 日 © 允许规范转载 打赏 赞赏作者 支付宝微信 赞 2 如果觉得我的文章对你有用,请随意赞赏