前前言❤️:本节课的内容及其重要也比较难懂,涉及到了传说中的三次握手和四次挥手的知识,为了避免出现纰漏我也是看了两遍才敢动笔写这篇补充笔记,举例和整理都花了不少时间,希望能对大家有帮助;其次是本节和上一节关系比较密切,建议先彻底搞懂再来看这节课。上节补充笔记:中科大计网学习记录笔记(十五):可靠数据传输的原理。
前言:学习视频:中科大郑烇、杨坚全套《计算机网络(自顶向下方法 第7版,James F.Kurose,Keith W.Ross)》课程
该视频是B站非常著名的计网学习视频,但相信很多朋友和我一样在听完前面的部分发现信息量过大,有太多无法理解的地方,在我第一次点开的时候也有相同的感受,但经过了一段时间项目的学习,对计网有了更多的了解,所以我准备在这次学习的时候做一些记录并且加入一些我的理解,希望能够帮助到大家。
往期笔记可以看专栏中的内容😊😊😊
文章目录
- [3.5 面向连接的传输:TCP](#3.5 面向连接的传输:TCP)
- [3.5.1 TCP 概述](#3.5.1 TCP 概述)
- [3.5.2 TCP 的报文段结构](#3.5.2 TCP 的报文段结构)
- [<1> 序号和确认号](#<1> 序号和确认号)
- [<2> 控制位](#<2> 控制位)
- [3.5.2 TCP 的往返延时和超时控制](#3.5.2 TCP 的往返延时和超时控制)
- [3.5.3 TCP 实现可靠数据传输概述](#3.5.3 TCP 实现可靠数据传输概述)
- [3.5.4 TCP 发送方](#3.5.4 TCP 发送方)
- [3.5.5 TCP 的重传机制](#3.5.5 TCP 的重传机制)
- [<1> 超时重传以及接收方 ACK 产生建议](#<1> 超时重传以及接收方 ACK 产生建议)
- [<2> 快速重传](#<2> 快速重传)
- [3.5.6 TCP 的流量控制](#3.5.6 TCP 的流量控制)
- [<1> 概述](#<1> 概述)
- [<2> 捎带技术](#<2> 捎带技术)
- [<3> 剩余缓冲区的计算](#<3> 剩余缓冲区的计算)
- [3.5.7 TCP 连接管理](#3.5.7 TCP 连接管理)
- [<1> TCP 连接建立 - 三次握手](#<1> TCP 连接建立 - 三次握手)
- [<2> 两次握手会带来哪些问题?](#<2> 两次握手会带来哪些问题?)
- [<3> TCP 连接的关闭 - 四次挥手](#<3> TCP 连接的关闭 - 四次挥手)
3.5 面向连接的传输:TCP
💡 TCP(Transmission Control Protocol,传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层协议,用于在网络上可靠地传输数据。
3.5.1 TCP 概述
- TCP 实现了 点对点 的通信
- TCP 提供了 可靠的、按顺序的 字节流服务
- 字节流代表需要上层自己维护边界
- TCP 是流水线协议,即一次可以发送多个报文段
- TCP 提供了流量控制,发送方根据接收方的接收能力进行发送速率的调整
3.5.2 TCP 的报文段结构
TCP 的报文段就是本层的数据单元 PDU,其由这几个部分构成
字段 | 长度(位) | 描述 |
---|---|---|
源端口号 | 16 | 指明发送端口 |
目的端口号 | 16 | 指明接收端口 |
序列号 | 32 | 标识数据段的顺序 |
确认号 | 32 | 对收到的数据进行确认 |
首部长度 | 4 | 表示 TCP 头部的长度 |
保留 | 6 | 保留字段,未使用,置为 0 |
控制位 | 6 | 标志位,用于控制连接和数据传输 |
窗口大小 | 16 | 接收端 可接收的数据量 |
校验和 | 16 | 用于检测传输过程中的错误 |
紧急指针 | 16 | 指示紧急数据的位置 |
选项和填充 | 可变 | 传输额外的控制信息和填充字节 |
<1> 序号和确认号
💡
MSS
(最大段大小)是 TCP 协议中的一个参数,用于指示在 TCP 报文段中能够容纳的最大数据量。它表示在不分段的情况下,一个 TCP 报文段能够携带的最大数据量。
TCP 将数据分割成一个一个报文段来发送出去,需要由编号来标识发出去的报文段的顺序。
- 序号:报文段的首个字节的的编号
- 确认号:期望 从另一端接收到的数据的编号,比如说现在接收到的编号为 53 那确认号就是 54 即其下一个需要的报文段的编号,与上一节中提到的协议的 ACK 相差 1
看一个案例
主机 A 向主机 B 发送一个字符,主机 B 将其回显出来;主机 A 发送标号为 42 的报文,同时请求标号为 79 的报文,B 返回标号为 79 的报文并且返回 ACK 请求标号为 43 的报文。
💡 为什么序号不是从零开始,而是要每次重新约定?
- 通过使用不从0开始的序号,TCP可以更容易地区分新的数据包和之前通信中滞留的数据包。
- TCP序号不是从0开始的主要原因是为了提高安全性和防止攻击。如果序号从0开始,那么攻击者可以通过伪造初始序号来发送欺骗性的数据包或发起拒绝服务攻击。
<2> 控制位
💡 在TCP报文头部中,控制位是指用来控制TCP连接状态和行为的位。
通过不同的控制位可以指示数据包的类型、状态或要执行的操作。
TCP报文头部的控制位包括以下几个:
- URG(Urgent): 表示紧急指针字段是否有效,用于指示该段是否包含紧急数据。
- ACK(Acknowledgment): 表示确认序号字段是否有效,用于指示该段是否包含确认数据。
- PSH(Push): 表示接收方应尽快交付数据给应用层,而不是等到缓冲区满或者等待更多数据。
- RST(Reset): 表示重置连接,用于中止连接或者响应异常情况。
- SYN(Synchronize): 表示建立连接,用于发起TCP连接的握手过程。
- FIN(Finish): 表示关闭连接,用于结束TCP连接的四次挥手过程。
3.5.2 TCP 的往返延时和超时控制
💡 TCP 中的超时时间通常是根据网络的往返时间(RTT)来动态设置的。RTT 是数据段从发送到接收并收到确认的时间,它是 TCP 连接中的一个重要指标,反映了数据在网络中传输的延迟。
- 平滑 RTT 估计(Smoothed Round-Trip Time): TCP 使用平滑 RTT 估计来计算当前的往返时间。每次发送数据段后,记录发送时间,并在收到对应的确认时计算 RTT。然后,使用加权移动平均等方法来计算平滑 RTT。
- 偏差估计(RTT Variation Estimate): TCP 还会估计 RTT 的变化范围,即 RTT 的偏差。这个值反映了网络延迟的 不确定性。TCP 使用偏差估计来确定超时时间的安全边界,以确保在不稳定的网络环境下也能保证数据的可靠传输。
- 超时时间设置: 综合考虑平滑 RTT 和 RTT 的偏差,TCP 设置超时时间为平滑 RTT 加上一个安全边界。这个安全边界通常是 RTT 的一个倍数,例如,可以设置为平滑 RTT 加上四倍的 RTT 偏差。
平滑的往返时间估计值:
E s t i m a t e d R T T = ( 1 − a ) ∗ E s t i m a t e d R T T + a ∗ S a m p l e R T T EstimatedRTT = (1- a)*EstimatedRTT + a*SampleRTT EstimatedRTT=(1−a)∗EstimatedRTT+a∗SampleRTT
- EstimatedRTT 是平滑的往返时间估计值;
- SampleRTTSampleRTT 是每次测量到的往返时间样本值;
- α 是平滑系数,通常取值在0到1之间,用于控制新样本值对于估计的影响程度。
估计出来往返时间的值,利用这个值来估计偏差
D e v R T T = ( 1 − β ) × D e v R T T + β × ∣ S a m p l e R T T − E s t i m a t e d R T T ∣ DevRTT=(1−β)×DevRTT+β×∣SampleRTT−EstimatedRTT∣ DevRTT=(1−β)×DevRTT+β×∣SampleRTT−EstimatedRTT∣
- DevRTT 是偏差估计值;
- SampleRTT 是当前的往返时间样本值;
- EstimatedRTT 是平滑的往返时间估计值;
- β 是用于平滑的系数,通常取值在0到1之间,用于控制新样本值对于估计的影响程度。
最后将超时时间设置为平滑的往返时间 + 四倍的估计偏差,通过这种设置可以降低拥塞。
3.5.3 TCP 实现可靠数据传输概述
💡 TCP 提供了可靠的数据传输服务。
🍀 TCP 在 IP 提供的不可靠服务的基础上建立了 RDT(可靠数据传输)。
- TCP 具有管道化的报文段
- 其具有累计确认的特点(像 GBN)
- 发送端有单个重传定时器(像 GBN)
- 接收端是否接收乱序没有规范,又接收端自己决定
💡 累计确认:接收端通常会 等待一小段时间(通常是几毫秒)来看是否有其他数据段到达。如果在此等待期间没有其他数据到达,接收端将发送一个 ACK,确认已接收到的数据。如果在等待期间有其他数据到达,接收端可能会将这些数据包含在同一个 ACK 中,从而合并确认消息。
💡 单个重传定时器:TCP 发送方的重传定时器设定在最早发送的那个字段,当超时的时候只是重发这个最早的字段,而不是像 GBN 那样重发全部。
🍀 TCP 发送方通过以下两种事件触发重传机制
- 超时,重发最早的未确认段
- 快速重传:收到重复的确认,在收到一个有效的确认后又收到三个 冗余的确认
3.5.4 TCP 发送方
💡 优先考虑简化的发送方,即忽略重复的确认和流量控制以及拥塞控制
💡 使用有限状态机(FSM)来描述
- 是一种抽象的计算模型,用于描述系统在不同状态之间的转换以及状态转换所触发的行为。有限状态机由一组状态、一组输入和一组状态转换规则组成。
- 使用圆来表示一种状态,使用连线来表示从一个状态到另一个状态的变迁,连线上的标注:分子表示引起状态变迁的事件,分母表示状态变迁的时候要进行的动作。
上图中标注了发送方 TCP 实体在 收到应用层数据、超时以及收到 ACK 的处理机制。
- 收到应用层数据的时候,TCP 实体船舰报文段和起始序列号(
create segment, seq
),发送的报文段的下一个数据的序列号设置为NextSeqNum + length(data)
,这就是上面提到的偏移量,比如我本次发送的数据的seq = 92
发送了8
个字节的数据,那下次数据的序列号就是92 + 8 - 1 + 1
也就是100
,然后启动一个定时器。 - 当超时的时候,重发具有最小序号的未确认段,而不是全部重发一遍
- 当收到 ACK 的时候,滑动窗口前移到
y
(累计确认,不一定是移动一位),如果现在还有未确认的段,就重新启动定时器,或者所有需要发送的数据已经确认完毕就终止定时器。
3.5.5 TCP 的重传机制
<1> 超时重传以及接收方 ACK 产生建议
先明确一点,无论发送方发送什么,接收方的 ACK 总是提出它此时需要的数据。
比如上图中的第二个例子,发送方因为数据过早超时再次发送了 seq = 92
的数据,但此时接收方已经接收到了编号 seq = 120
以前的所有数据,所以此时请求的是 seq = 120
上图描述的是 TCP 接收方的累计确认机制,即其 ACK 中请求的报文,表示这个报文以前的所有报文都已经收到,而不是类似于 SR 协议那样每次收到一个报文都发送一个 ACK。
关于产生 TCP ACK 的建议:
- 第一条建议就是延迟确认机制,即等待一段时间如果没有新的报文段到来再发送 ACK,避免对发送方造成过多的干扰。
- 第二条建议即积累两个报文段一起发送,比如说现在到达了
seq = 92
8
个字节,先暂时等待不发,此时又到了一个seq = 100
20
个字节,此时直接发送 ACK(120)。 - 第三种和第四种情况处理的是乱序接收的情况,即当收到乱序的报文段后立即发送 ACK,或者说收到的报文段填充了从
gap
起点的一部分gap
,此时也立即发送新的 ACK。
💡 最后两条的案例演示
比如说这是接受方的滑动窗口,绿色表示已经接收到的,黄色表示未确认的,当发现乱序的时候立即发送一个 ACK 来请求黄色的部分。
当黄色部分被填补了一部分,此时也是立即发送确认来请求新的黄色块,但如果完全填补就移动窗口到最右端恢复正常的请求顺序。
<2> 快速重传
💡 因为发送方的超时时间设置的比较保守,所以需要有一种机制来提高其效率。
当报文段丢失的时候,会引起多个重复的 ACK
比如这个例子,和上面提到的 TCP ACK 的建议相同,乱序到达的时候接收方会立即发送请求填补空缺的 ACK,即在 40
60
70
80
到达的时候均请求 50
的报文段,当冗余请求累积到三个的时候,发送方会触发快速重传机制,立即 重发 seq = 50
的报文段。
快速重传算法
3.5.6 TCP 的流量控制
💡 因为接收方的接收能力是有限的,如果发送方发送的过快会导致数据的溢出,所以发送方要根据接收方的剩余窗口来决定自己发送的数据的总大小。
<1> 概述
因为上层读取数据需要时间,所以暂时未读取的数据要存在接收方的缓冲区(buffer)中,这个缓冲区同时也接收发送方发送的数据,剩余的缓冲区就是总缓冲区的大小减去此时缓冲区中的数据大小。
RecvBuffer
大小通过socket
的选项来设置,通常默认的大小为4096
字节。- 很多操作系统会自动的调整
Buffer
<2> 捎带技术
发送方得知了接收方的剩余缓冲区大小的时候,保证其发送的字节数 ≤ rwnd
值
💡 关于捎带技术(Piggybacking):
- 捎带技术(Piggybacking)是一种优化网络通信的方法,常见于TCP协议中。
- 它利用已有的数据包来携带额外的信息,而不是单独发送一个新的数据包。
- 发送方在作为数据的发送方的时候,同时也作为 ACK 的接收方
下面来看一个例子
农民 1 卖给农民 2 一群羊,农民 2 寄信来说羊收到了
然后农民 2 再次寄信将钱发给农民 1
💡 那为什么不直接寄信说羊收到的时候就将钱寄过去呢?
- 这就是捎带技术,利用已有的数据包来携带额外的信息,而不是单独发送一个新的数据包。
<3> 剩余缓冲区的计算
💡 接收方维护两个数据来实现剩余 buffer 的计算
- 第一个字段是最后一次读的数据,第二个是最后一次收到的数据
- 这两个编号相减就是此时 存储在 缓冲区中的数据,再用总的缓冲区大小减去这个数据,就得到剩余的总大小。
3.5.7 TCP 连接管理
<1> TCP 连接建立 - 三次握手
- 客户端发送连接请求:客户端首先向服务器发送一个 SYN(同步)报文段,其中设置了一个初始序列号(ISN)用于标识数据流的起始位置,并指明客户端希望建立连接的端口号。
- 服务器确认连接请求:服务器收到客户端的 SYN 报文段后,会回复一个 SYN+ACK 报文段,其中 SYN 标志位表示同步,ACK 标志位表示确认。服务器也会为自己生成一个 ISN,并将其发送给客户端,同时确认客户端的序列号。
- 客户端确认连接请求:客户端收到服务器的 SYN+ACK 报文段后,会发送一个 ACK 报文段作为确认。此时,TCP 连接已经建立起来,通信双方可以开始进行数据传输。
💡 三次握手就是客户端发送连接请求,服务器发送同意连接的请求,客户端再次发送确认请求,来表示 客户端是活跃的。
<2> 两次握手会带来哪些问题?
💡 两次握手导致的问题是由于连接是单方维护的,只是由服务器去维护连接资源,而客户端不去维护,这就导致了双方状态的不对等,三次握手通过在连接建立的过程中引入客户端的确认,解决了这个问题,使连接状态在客户端和服务器之间得到了正确的同步。
- 连接重用问题:在两次握手的情况下,服务器在发送 SYN+ACK 报文段后,就已经认为客户端的连接请求被接受,可以开始传输数据。但是客户端可能并没有接收到服务器的确认,因此可能会导致服务器误认为连接已经建立,从而发送数据。如果这些数据到达客户端,而客户端并没有发送对应的 ACK 确认,那么服务器会误以为这是一个新的连接请求,导致资源浪费和安全问题。
- 连接状态不对称:在两次握手的情况下,客户端和服务器都会发送 SYN 报文段,但只有服务器在发送 SYN+ACK 报文段时会确认客户端的序列号,而客户端在收到服务器的确认后并不会再次确认服务器的序列号。这样会导致连接状态在客户端和服务器端之间不对称,可能会引发一些问题,例如对方不是真正的对方。
- 欺骗性连接问题 :在两次握手的情况下,攻击者可以发送一个伪造的 SYN 报文段给服务器,如果服务器回复了 SYN+ACK 报文段,那么就建立了一个 不完整的连接,攻击者可以利用这种连接进行攻击,例如进行拒绝服务攻击。
💡 拒绝服务(Denial of Service,DoS)攻击是一种旨在使目标系统或网络资源无法提供正常服务的恶意行为。攻击者通过不断发送大量的请求或者恶意数据包,耗尽目标系统的资源(如带宽、处理能力、内存或存储空间),导致正常用户无法访问或使用该系统或网络资源。
<3> TCP 连接的关闭 - 四次挥手
- 发送关闭连接请求: 当一方决定关闭连接时(通常是应用层发出关闭连接的指令),它会向另一方发送一个 FIN 包,表示它不再发送数据了,但仍然愿意接收数据。
- 确认关闭连接请求: 接收到关闭请求的一方会发送一个 ACK 包作为确认,表示它收到了关闭请求。
- 关闭连接: 发送确认后,这一方就开始进入关闭连接的状态,它不再发送新的数据,但仍然会继续接收数据。它也可以继续发送剩余的数据。
- 发送关闭连接请求: 当这一方确定自己的数据都发送完毕后,就会发送一个 FIN 包给另一方,表示它也要关闭连接了。
- 确认关闭连接请求: 接收到关闭请求的另一方会发送一个 ACK 包作为确认。
- 关闭连接: 发送确认后,另一方也开始关闭连接。至此,连接就彻底关闭了。
💡 四次挥手确保了双方都能够安全地关闭连接,同时允许双方在关闭连接之前完成他们的数据传输;三次握手四次挥手都是为了保证双方的状态统一,即一方达到某一状态之前需要告知另一方,需要收到对方的 ACK。在建立连接时,三次握手确保了双方都已准备好通信;在关闭连接时,四次挥手确保了双方都能够安全地完成数据传输并关闭连接,避免了半开连接状态和潜在的数据丢失问题。