【计算机网络】详解传输层 TCP 协议

📎 前言

传输层可以负责数据能够从发送端传输接收端. 其中有两个特别重要的协议, 一个是UDP协议, 一个是TCP协议. 前面的文章已经介绍了UDP协议, 本文我们介绍更可靠的TCP协议.

TCP,即Transmission Control Protocol,传输控制协议。人如其名,是对数据的传输进行一个详细的控制。

1. TCP协议段格式

在这里插入图片描述
以上就是TCP协议段的格式.

  • 源/目的端口号: 表示数据是从哪个进程来,到哪个进程去;
  • 32位序号/32位确认号
  • 4位TCP报头长度:表示该TCP头部有多少个32位bit(有多少个4字节);所以TCP头部最大长度是15 * 4 = 60字节
  • 6位标志位:
    • URG:紧急指针是否有效
    • ACK:确认号是否有效
    • PSH:提示接收端应用程序立刻从TCP缓冲区把数据读走
    • RST:对方要求重新建立连接;我们把携带RST标识的称为复位报文段
    • SYN:请求建立连接;我们把携带SYN标识的称为同步报文段
    • FIN:通知对方,本端要关闭了,我们称携带FIN标识的为结束报文段
  • 16位窗口大小
  • 16位校验和:发送端填充,CRC校验。接收端校验不通过,则认为数据有问题。此处的检验和不只包含TCP首部,也包含TCP数据部分。
  • 16位紧急指针:标识哪部分数据是紧急数据;
  • 40字节头部选项

2. TCP实现机制

TCP对数据传输提供的管控机制,主要体现在两个方面:安全和效率

这些机制和多线程的设计原则类似:保证数据传输安全的前提下,尽可能的提高传输效率。

2.1 确认应答(保证可靠性最核心机制)

在这里插入图片描述
根据TCP协议段中的标志位就可以分辨出当前报文是一个普通报文还是一个确认应答报文.

  • 当ACK为 0 时表示这是一个普通的报文, 此时只有32位序号是有效的.
  • 当ACK为 1 时表示这是一个应答报文, 此时这个报文的序号的确认序号都是有效的. (确认报文的序号和普通报文的序号没有关联关系)

由于TCP是按照字节流传播的, 因此TCP将每个字节的数据都进行了编号。即为序列号
在这里插入图片描述
每一个应答报文都带有对应的确认序列号,意思是告诉发送者,我已经收到了哪些数据;下一次你从哪里开始发.

2.2 超时重传

在这里插入图片描述

  • 主机A将数据发送给B, 其中可能因为网络拥堵等原因导致数据丢失而无法到达主机B. 这时主机A就会在一个特定的时间内未收到B的确认应答而进行重发.

但是,主机A未收到B发来的确认应答,也可能是因为ACK丢失了. 但是发送方并无法判断具体是哪一种情况.在这里插入图片描述
通过上图我们不难看出, 这种情况下主机B就会重复的收到很多数据. 那么TCP协议就需要做到识别出哪些数据报是重复的, 并要把重复的数据报丢弃掉.

这时候就需要利用到前面提到的序列号, 就可以容易的做到去重的效果.

2.3 连接管理机制[三次握手四次挥手]

一般情况下, TCP都是要经过三次握手和四次挥手来进行连接管理的.
在这里插入图片描述

三次握手建立连接

“握手"是一个形象的说法, 当两台主机要建立连接时, 发送方首先发送一个"打招呼"的数据, 这个数据不会带有业务信息. 完成建立连接的过程就需要三个这样的"打招呼” 数据交互.
在这里插入图片描述
“ACK"我们已经了解了, 就是发出的应答报文. 这里的"SYN"是申请建立连接的请求. 即"同步报文段”. 如果在报文段标志位中SYN为1 就是一台主机想要尝试和另一台建立连接.

三次握手的意义
1. 投石问路

“三次握手”, 也是一种保证可靠性的机制. 其中一个意义类似于"投石问路". 一个简单的生活小例子在这里插入图片描述
当且仅当这三次消息确认完毕后, 双方才分别能确认连接是正常的, 而这些也是后续进行可靠传输的前提条件.

这样的目的正是为了验证网络通信是否畅通, 以及验证每个主机的发送能力和接收能力是否正常.

2. 协商必要的参数

三次握手也能起到"消息协商"这样的效果. TCP通信的过程中, 涉及到的一些参数, 若需要双方保持一致的. 也可通过这种方式来确定参数具体是多少.
一个小例子
在这里插入图片描述
这样双方就可以通过三次握手的方式进行消息协商. 使客户端和服务器使用相同的参数去进行消息的传输.

四次挥手断开连接

连接使通信的双方各自在内存中保存了对端的相关信息. 如果某时刻不需要连接了, 就需要双方及时的释放存储空间.
在这里插入图片描述
这里出现的 FIN 也是六个标志位其中的一个. 它为1时代表了 结束报文段.

FIN的触发是由应用程序代码来控制的. 当程序调用 socket.close()或进程结束时就会触发 FIN. 相比之下, ACK是由系统内核控制的. 收到 FIN 时就会立马返回ACK.

如果断开连接的过程中丢包了怎么办.
网络通信的过程中, 难免会遇到丢包的情况, 但如果在断开连接的过程中出现了丢包, TCP会怎么处理呢?

我们根据四次挥手的简易图中来分析, 若第一组 FIN/ACK 出现丢包, 这时只需要客户端重传FIN即可. 但如果是第二组 FIN/ACK 出现了丢包. 我们做如下分析.

在这里插入图片描述
站在A的角度, 当收到了B发来的FIN, 并且已经发出了ACK. 此时A就应视为 四次挥手 已经结束了. 但此时A很明显并不可以直接释放连接. 因为最后一个ACK在传输过程中仍可能丢包.

因此, 就需要在A发出最后一个ACK后让连接再持续一段时间. 若超过这个特定的时间后还没有收到对方重传的FIN, 就认为ACK已经被对方收到了, 这时A才可正确的释放连接.

而这个等待时间一般为网络上任意两点之间传输的最大时间*2(MSL).

2.4 滑动窗口

刚才我们讨论了确认应答策略,对每一个发送的数据段,都要给一个ACK确认应答。收到ACK后再发送下一个数据段。这样做有一个比较大的缺点,就是性能较差。尤其是数据往返的时间较长的时候。
在这里插入图片描述
既然这样一发一收的方式性能较低,那么我们一次发送多条数据,就可以大大的提高性能(其实是将多个段的等待时间重叠在一起了), 如下图所示.
在这里插入图片描述

  • 窗口大小指的是无需等待确认应答而可以继续发送数据的最大值。上图的窗口大小就是4000个字节(四个段)。
  • 发送前四个段的时候,不需要等待任何ACK,直接发送;
  • 收到第一个ACK后,滑动窗口向后移动,继续发送第五个段的数据;依次类推;
  • 操作系统内核为了维护这个滑动窗口,需要开辟 发送缓冲区 来记录当前还有哪些数据没有应答;只有确认应答过的数据,才能从缓冲区删掉;
  • 窗口越大,则网络的吞吐率就越高(但窗口不能无限大, 否则就相当于不用等待ACK. 也就又成了不可靠传输了);
    在这里插入图片描述
    看到如此"复杂"的传输方式, 我们也不禁会想到, 如果在传输过程中丢包了该怎么办呢?

情况一: 数据包已经抵达, 但ACK丢了.
在这里插入图片描述
如果是一部分的ACK丢了, 不需要做任何处理也是正确的. (当然不包括所有ACK全部丢的情况, 这时一定是网络出现重大故障了). 因为当主机A收到之后的ACK时也包含了收到前面的数据的含义.

情况二: 数据报丢了
在这里插入图片描述

  • 当某一段报文段丢失之后,发送端会一直收到 1001 这样的ACK,就像是在提醒发送端 “我想要的是 1001” 一样;
  • 如果发送端主机连续三次收到了同样一个 “1001” 这样的应答,就会将对应的数据 1001 -2000 重新发送;
  • 这个时候接收端收到了 1001 之后,再次返回的ACK就是7001了(因为2001 - 7000)接收端其实之前就已经收到了,被放到了接收端操作系统内核的接收缓冲区中;

这种机制被称为 “高速重发控制”(也叫 “快重传”)

2.5 流量控制

该机制作为滑动窗口的补充. 滑动窗口越大, 传输效率也就越高. 但如果窗口太大就可能使接收方或者中间链路处理不过来, 就容易出现丢包. 这样反而影响了效率.

在这里插入图片描述
如上图, A 这边的生产速度很快, 而B如果消费速度跟不上, 接收缓冲区就会越来越多, 最终可能就会满了, 这时如果继续发送数据就会出现丢包的情况.

因此, TCP支持根据接收端的处理能力,来决定发送端的发送速度. (窗口大小)也就是流量控制, 给滑动窗口踩踩刹车, 避免窗口太大导致效率降低.

  • 接收端将自己可以接收的缓冲区大小放入 TCP 首部中的 “窗口大小” 字段,通过ACK端通知发送端;
  • 窗口大小字段越大,说明网络的吞吐量越高;
  • 接收端一旦发现自己的缓冲区快满了,就会将窗口大小设置成一个更小的值通知给发送端;
  • 发送端接受到这个窗口之后,就会减慢自己的发送速度;
  • 如果接收端缓冲区满了,就会将窗口置为0;这时发送方不再发送数据,但是需要定期发送一个窗口探测数据段,使接收端把窗口大小告诉发送端。
    在这里插入图片描述
    我们看回到TCP的协议格式中的这两项在这里插入图片描述

其中, 16位窗口大小字段就表示了当前接收方缓冲区剩余的空间大小, 将这个数字返回给发送方, 就可以作为发送方下一轮发送的参考依据了.

那么这里的16位是不是就意味着窗口大小最大就是64KB了呢? 并不是.
下面这个选项字段中有一个选项为窗口大小扩展因子. 实际的大小其实是16位窗口大小<<扩展因子(移位运算). 此时能表示的窗口大小就非常大了.

2.6 拥塞控制

虽然TCP拥有了滑动窗口这个高效可靠的机制,但如果在网络刚启动的阶段就发送大量的数据出去,仍然会引发一系列的问题.

TCP引入了慢启动机制, 先发送少量的数据, 摸清楚当前网络拥堵的状态,再据此决定按照多大的速度传输数据. 在这里插入图片描述

  • 此处引入一个概念为拥塞窗口
  • 发送开始时, 定义拥塞窗口大小为1;
  • 每收到一个ACK应答,拥塞窗口加1;
  • 每次发送数据包时,将拥塞窗口接收端主机反馈的窗口大小作比较, 取较小的值作为实际发送的窗口.

像上面这样的拥塞窗口增长速度,是指数级别的。“慢启动” 只是指初使时慢,但是增长速度非常快。

  • 为了不增长的那么快,因此不能使拥塞窗口单纯的加倍。
  • 此处引入一个叫做慢启动的阈值
  • 当拥塞窗口超过这个阈值的时候,不再按照指数方式增长,而是按照线性方式增长在这里插入图片描述
  • 当TCP开始启动的时候,慢启动阈值等于窗口最大值
  • 在每次超时重发的时候,慢启动阈值会变成原来的一半,同时拥塞窗口置回1;

2.7 延迟应答

如果接收数据的主机立刻返回ACK应答,这时候返回的窗口可能比较小。

  • 假设接收端缓冲区为1M。一次收到了500K的数据;如果立刻应答,返回的窗口就是500K;
  • 但实际上可能处理端处理的速度很快,10ms之内就把500K数据从缓冲区消费掉了;
  • 在这种情况下,接收端处理还远没有达到自己的极限,即使窗口再放大一些,也能处理过来;
  • 如果接收端稍微等一会再应答,比如等待200ms再应答,那么这个时候返回的窗口大小就是1M;

窗口越大,网络吞吐量就越大,传输效率就越高。我们的目标是在保证网络不拥塞的情况
下尽量提高传输效率
在这里插入图片描述

2.8 捎带应答

在延迟应答的基础上,我们发现,很多情况下,客户端服务器在应用层也是 “一发一收” 的。意味着客户端给服务器说了 “How are you”,服务器也会给客户端回一个 “Fine, thank you”;那么这个时候ACK就可以搭顺风车,和服务器回应的 “Fine,thank you” 一起回给客户端.
在这里插入图片描述

言至于此, 为什么TCP这么复杂?因为要保证可靠性,同时又尽可能的提高性能.

TCP保证可靠性的机制

  • 校验和
  • 序列号(按序到达)
  • 确认应答
  • 超时重发
  • 连接管理
  • 流量控制
  • 拥塞控制

TCP提高性能的机制

  • 滑动窗口
  • 快速重传
  • 延迟应答
  • 捎带应答

🎉 总结

🎇到这里本篇文章就结束了,感谢大家的阅读。非常希望大家可以提出宝贵的建议!!
🎇这篇文章介绍了传输层中一个特别重要的协议——TCP协议. 通过对TCP实现机制的了解我们更加确定了TCP相对于UDP协议的可靠性与高效性。
🎇更多相关知识请关注博主其他文章.
🎇希望大家可以点赞+收藏+评论支持一下噢!
🎇望继续保持关注~

  • 15
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jester.F

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值