TCP的十个核心机制

news2024/11/14 14:01:12

目录

  • 前言
  • 一 到 三
  • 四. 滑动窗口
  • 五. 流量控制
  • 六. 拥塞控制
  • 七. 延时应答
  • 八. 捎带应答
  • 九. 面向字节流
  • 十. 异常处理
  • 总结

前言

TCP协议是传输层的重点协议, 负责将数据从发送端传输到接收端.
TCP协议是传输控制协议, 顾名思义也就是对数据的传输进行控制的协议.
TCP 协议有很多, 我们今天就介绍其最重要的十个核心机制, 即 :

  1. 确认应答
  2. 超时重传
  3. 连接管理
  4. 滑动窗口
  5. 流量控制
  6. 拥塞控制
  7. 延迟应答
  8. 捎带应答
  9. 面向字节流
  10. 异常处理

一 到 三

确认应答及超时重传(保证TCP的可靠性)

连接管理(三次握手及四次挥手)

下面就详细讲解其它七点特性.

四. 滑动窗口

相比于 UDP 来说 TCP 的效率是很低的, 使用 TCP 最重要的还是为了保证可靠性, 在可靠性的基础上再来尽可能高的提高效率, 当然再怎么提高都不如 UDP, 这只是尽可能的止损. (提高可靠性, 往往要损失效率, 所谓鱼和熊掌不可兼得)

什么是滑动窗口呢 ? 滑动窗口又是如何提高效率的呢 ?
首先, 我们回到两台主机间的数据传输, 我们知道 TCP 因为要保证数据的可靠性, 因此在数据接收方在接收到数据后, 就会发送一个 ack 报文, 来告知发送方已接收到数据请发下一条数据, 具体场景如下:
在这里插入图片描述
观察上图, 我们发现这些数据都是一条一条发送, 发送完了一条还得对方回应再发送, 我们是不是可以对其进行优化, 使得等待时间变短. 滑动窗口就是通过减少等待时间, 来增大传输效率的.
具体场景如下:
在这里插入图片描述
可以看到, 滑动窗口是通过批量发送数据来达到减少等待时间的目的.
这里是批量发送四个数据, 再统一等待 ack, 每次收到一个 ack 就发下一条, 用一份等待时间等待多个ack, 这样总的等待时间变短了, 总体效率也就提高了.

批量传输为啥要叫滑动窗口呢 ?
批量传输不是无限传输, 它是发送一定的数据然后等待 ack, 每等到一个 ack 就立即再传输一个数据, 这样总的等待数量就不变, 我们把批量等待数据的大小就叫做窗口大小, 场景如下:
在这里插入图片描述

电脑的传输处理数据能力是非常快的, 因此这个窗口就像一直处在滑动状态.

那如果在批量传输过程中出现丢包情况怎么办 ?
这里我们可以分两种情况, 一种是数据报抵达但 ack 丢了, 另一种是数据报丢了.

情况一 : ack丢了.
在这里插入图片描述
图中的 ack 丢了一半多了, 丢包率相当高了, 这种情况有啥影响吗 ?

其实即是丢了这么多 ack, 对可靠性也没任何影响.
我们知道返回的 ack 中有确认序号, 确认序号的含义就是该序号之前的数据已经收到了.

注意 : 后一个 ack 能够涵盖前一个 ack 的意思, 举个例子 :
我们看图中返回的确认序号 1001 丢了, 但 2001 到了, 这个时候接收方收到 2001 之前的数据, 发送方即使没收到 1001, 根据 2001 也知道前面的数据都收到了, 接着就是发下面的数据了.

那如果最后一条数据丢了呢 ?
很简单, 超时重传.(发送方不知道是ack丢了还是数据包丢了)

情况二 : 数据包直接丢了
在这里插入图片描述
上图中 1001-2000 的数据包丢了, 接收方接收到的数据, 是按照序号在缓冲区进行排列的, 如下 :

在这里插入图片描述

B接收到 2001-3000, 3001-4000, 4001-5000 时就会发现少了 1001-2000 的数据, 这个时候返回的确认序号就是 1001, 即向A索要 1001 开始的数据, 如果A一直不发送, 那 B 会一直索要, 当 B 发送了三个重复确认序号时, A 就会发现事情不简单, 就会重新发送 1001-2000 的数据, 当 B 接收到后, 就不是发送 2001 的确认序号了, 而是索要接下来未发送的数据, 也就是 5001.
在这里插入图片描述

注意 : 上述重传过程没有任何冗余操作, 丢了的数据才会进行重传, 整体速度比较快, 又叫快速重传.

滑动窗口及快速重传是在批量传输大量数据时才会采用的措施, 当数据量少, 且比较低频时, 就不会这样搞了, 此时依靠确认应答及超时重传.

五. 流量控制

为啥要流量控制呢 ?

上面讲了滑动窗口, 批量发送, 窗口越大, 批量发送的数据就越多, 传输的效率也就越大了.
但滑动窗口大小可不是无限大的, 得保证可靠传输, 如果一次性发的数据包太多了, 瞬间就会将接收方的数据接收缓冲区给冲满, 接下来继续发送就会丢失数据包, 得不偿失.
通过流量控制, 本质上就是让接收方来限制发送方的发送速度.

它是如何控制的呢 ?
其实在 TCP 报文中, 携带了 “窗口大小” 这样的字段, 如下 :
在这里插入图片描述

当 ack 为 1 时, 此时窗口大小字段就会生效, 这里的值只是建议发送方发送的窗口大小.

那接收方是如何计算窗口大小的呢?
接收方直接拿缓冲区剩余空间作为窗口大小.

![在这里插入图片描述](https://img-blog.csdnimg.cn/18920987b65647fabf469b067969b07b.png
① : 当 B 收到数据时, 根据缓冲区大小计算窗口大小, 并写入 ack 中.
② : A 收到窗口大小后, 批量发送适量的数据.
③ : B 每次收到数据时, 都会计算一次窗口大小, 并写入 ack 中.
④ : A 收到窗口大小为 0 的 ack 后, 就不再发送剩下的数据包了, 而是每隔一段时间发一个窗口探测报文, 如果探测到了窗口大小不为零, 则说明有空间了, 可以继续发送.
⑤ : B 腾出空间了, 将窗口大小写入 ack 中, 并索要接下来的数据.

应用程序从 socket 读数据, 就是在消费缓冲区里的数据, 读完就腾出空间了.

注意 : 上述过程是将返回的窗口大小作为实际窗口大小, 实践中可能会有出入.
窗口大小 = 流量控制 + 拥塞控制

六. 拥塞控制

为啥说滑动窗口大小取决于流量控制和拥塞控制呢 ?
如果说流量控制衡量了接收方的接收能力, 那么拥塞控制就是衡量传输路径的数据处理能力.

两个主机间进行交互, 并不是直接点对点进行交互的, 而是通过很多中间节点来实现数据传输.
场景如下 :
在这里插入图片描述
如果在数据传输过程中, 有一台设备处于瓶颈状态, 都会对整体传输数率产生明显影响.(短板效应)

拥塞控制就是衡量中间节点的传输能力, 它是通过实验的方式来找到一个合适的发送速率.
在这里插入图片描述
刚开始的时候, 按照一个小速率发送, 如果不丢包就提高速率(窗口大小), 如果出现丢包, 则把速率再调小.
可以看到在拥塞窗口达到一定值(阈值)之前, 是按指数级增长, 之后就是线性增长, 避免一下超出上限很多, 可以慢慢接近传输上限. 当增长到一定程度时, 出现丢包情况, 则认为已经达到当前路径的传输上限了. 这时就开始下一轮的测试, 但是这次的阈值比前一次小了, 以期望达到更准确的传输上限.

七. 延时应答

延时应答是为了提高 TCP 的传输效率.

延时应答是啥意思呢 ?
就是返回的 ack 不是立即发送, 而是等待一会儿, 再发送.

为啥延时应答可以提高传输效率呢 ?
我们知道 TCP 中决定传输效率的关键元素就是窗口大小.
窗口大小又取决于 流量控制及拥塞控制.
而流量控制的关键又是接收方的接收缓冲区的剩余空间大小, 延时应答就是通过这点来提高传输效率的. (当然不是扩大缓冲区)

具体原理如下 :
在这里插入图片描述
当接收方接收到一个数据时, 就会返回一个 ack, 这个 ack 中就包含了窗口大小, 假设为 n.
同时应用程序也在消费缓冲区的数据, 也就是说缓冲区的大小在时刻变化, 这个时候如果稍等片刻再返回 ack, 此时 ack 中的窗口大小大概率比 n 大.
(数据交互都要进行封装和分用, 此时减少发送频率还提高了窗口大小, 无疑提高了传输效率)

总结 :
延时应答就是通过延时发送 ack, 来让应用程序多消费点数据, 达到增大窗口的效果, 此时就发送方的发送效率就得到提高.(同时也满足让接收方处理的过来)

八. 捎带应答

捎带应答是基于延时应答来实现的.

客户端服务器间的通信模型通常是 “一问一答” 的.

客户端服务器间的通信模型:

  1. 一问一答 : 绝大部分服务器都采用这种方式.
  2. 多问一答 : 上传文件.
  3. 一问多答 : 下载文件.
  4. 多问多答 : 游戏串流.

像前面学的 TCP 四次挥手 : (链接 : 三次握手及四次挥手)
在这里插入图片描述
服务器收到客户端发出的断开请求 fin 后, 由系统内核立即返回一个 ack, 然后服务器执行到 close 方法也发送一个 fin.

服务器发送的 ack 及 fin 本来时机是不同的, 但由于延时应答, 此时 ack 就可能和 fin 合成一个数据报, 提高了传输效率. (数据交互都是要进行封装和分用的, 减少交互次数就可以提高效率)

九. 面向字节流

面向字节流可以让我们读写数据时依据需求来读写.

比如 :
写100个字节数据时,可以调用一次write写100个字节,也可以调用100次write,每次写一个字节;
读100个字节数据时,也完全不需要考虑写的时候是怎么写的,既可以一次read 100个字节,也可以一次read一个字节,重复100次;

这也随之引来一个问题 ----“粘包问题”.
什么是粘包问题呢 ?

假设以下场景 :
在这里插入图片描述

主机A 与 主机B对话, 其中它们的缓冲区如下 :
在这里插入图片描述

站在传输层的角度来看, TCP 是一个报文一个报文发送过来的, 按照序号排好序放在缓冲区的.
但在应用层角度来看, 缓冲区中只是一串连续的字符, 没有规律.

回到上图, 如果仅看缓冲区, 我们是否可以分出一句话呢 ?
以 B 的缓冲区来看, 可以明显看出每句话都以 “兄弟” 开头, 也就不难分辨每一句话了.
但 A 的缓冲区不同, 它是毫无规律的, 我们区分不出来一句话哪里到哪里.
这就是 “粘包问题”.

简单来说, 粘包问题就是 当 A 给 B 发送多个应用层数据报后, 这些数据都在 B 的缓冲区中排好序, 紧紧挨着, 此时 B 的应用程序在读数据的时候, 就难区分从哪里到哪里是一个完整的应用层数据报, 就很容易读错(读出半个包 / 一个半包…)

如何解决粘包问题呢 ?
对于定长的包,保证每次都按固定大小读取即可;
对于变长的包,可以在包头的位置,约定一个包总长度的字段,从而就知道了包的结束位置;
对于变长的包,还可以在包和包之间使用明确的分隔符(应用层协议,是程序猿自己来定的,只要保证分隔符不和正文冲突即可);

通常我们是自定义分隔符来解决问题.

ps : 那 UDP 协议会有这种问题吗 ?
对于UDP,数据进入缓冲区后,UDP的报文长度仍然在。同时,UDP是一个一个把数据交给应用层的。就有很明确的数据边界。
站在应用层的角度,使用UDP的时候,要么收到完整的UDP报文,要么不收, 不会出现 “半个” 的情况。

十. 异常处理

这里异常分四种情况 :

  1. 进程关闭 / 进程崩溃
  2. 主机关机 (正常流程关机)
  3. 主机掉电 (直接拔电源, 不考虑笔记本)
  4. 网线断开

1.进程关闭 / 进程崩溃

虽然进程没了, 但 socket 是文件, 进程结束会释放资源描述符, 仍然可以进行四次挥手.

2.主机关机

会先杀死所有的用户进程, 然后关机.
杀死进程就会触发四次挥手, 可能它还没挥完手就关机了, 比如 :
我这边发送 fin, 对方回了个 ack, 这时我电脑已经关了, 我收不到 ack 了, 对方发完 ack 后, 又发了 fin, 结果发现我这边没响应, 此时对端就会重传 fin, 重传几次发现都没有 ack, 那它就会重置连接, 如果还不行, 就会释放连接.

3.主机掉电

瞬间主机就关机了, 来不及进行任何挥手操作.
这又分两种情况 :

  1. 对端是发送方
    对端发送数据报后接收不到 ack, 就会超时重传, 再收不到就会重置链接, 还不行就释放连接.
  1. 对端是接收方
    对端是接收方就无法立即知道, 我这边是没来的及发还是已经没了.
    其实 TCP 内置了 “心跳包” 保活机制, 它是周期性的, 如果没了就是挂了.
    虽然对端是接收方, 但是对端也会定期发送一个心跳包(ping), 我这边也会返回一个(pong).
    如果每个 ping 发出后都得到了 pong 那没问题, 但如果多个 ping 发出去都得不到一个 pong, 那对方多半是挂了. 那就释放连接了.

4.网络断开

其实这和第三点一样.
两个主机进行通信就是基于网络, 如果网络都没了, 那和挂了没区别.

总结

TCP 的传输效率是远不及 UDP 的, 正是因为 TCP 要保证传输的可靠性, 所以牺牲了效率, 但是 TCP 又以滑动窗口, 流量控制, 拥塞控制, 延时应答, 捎带应答等等特性, 来尽可能提高效率. (尽可能减少可靠性带来的效率损失)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/674317.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

android存储3--初始化.unlock事件的处理

android版本:android-11.0.0_r21http://aospxref.com/android-11.0.0_r21 概述:收到unlock事件后,StorageSessionController、vold、storaged模块进行各自初始化操作。 一、StorageManagerService::onUnlockUser处理unlock事件 设备解锁后…

openlayers瓦片的使用

OpenLayers是一个用于WebGIS客户端的地图开发库,支持多种地图。在使用瓦片时,先将自己需要的瓦片下载,下载好的瓦片会分层,越高的层级瓦片的数量余额多。 使用时可以引入 ol.js 文件,和 ol.css 文件,或者使…

机器学习 | 实验五:LDA

LDA的思想:“投影后类内方差最小,类间方差最大”。即数据在低维度上进行投影,投影后希望每一种类别数据的投影点尽可能的接近,而不同类别的数据的类别中心之间的距离尽可能的大。 假设我们有两类数据分别为红色和蓝色,…

关于socket编程中FD_XXX以及select函数的理解

文章目录 01 | 宏接口定义02 | 使用方法03 | 服务端代码示例 学习socket编程的时候看到很多FD开头的宏定义和函数,这里记录一下这些宏定义和函数的含义及处理流程 01 | 宏接口定义 fd_set fd_set 是一种表示文件描述符的集合类型,在socket编程中&#xf…

计算机网络——自顶向下方法(第三章学习记录)

本章学习运输层 运输层位于应用层和网络层之间,是分层的网络体系的重要部分,该层为运行在不同主机上的应用进程提供直接的通信服务起着至关重要的作用。 运输层协议为运行在不同主机上的应用进程之间提供了逻辑通信(logic communication)功能。从应用程…

CSS3-补充-伪元素

伪元素 作用:在网页中创建非主体内容,开发中常用CSS创建标签,比如装饰性的不重要的小图 区别: 1 元素:HTML 设置的标签 2 伪元素:由 CSS 模拟出的标签效果 …

EMC学习笔记(七)阻抗控制(一)

阻抗控制(一) 1.特征阻抗的物理意义1.1 输入阻抗1.2 特征阻抗1.3 偶模阻抗、奇模阻抗、差分阻抗 2.生产工艺对阻抗控制的影响 1.特征阻抗的物理意义 1.1 输入阻抗 在集总电路中,输入阻抗是经常使用的一个术语 ,它的物理意义是: …

FreeRTOS实时操作系统(六)列表与列表项

系列文章目录 文章目录 系列文章目录简要概念列表列表项迷你列表项 相关API函数初始化列表列表项初始化列表项插入(升序)末尾列表项插入列表项删除 实战实验 简要概念 列表是 FreeRTOS 中的一个数据结构,概念上和链表有点类似,列…

ubuntu环境下测试硬盘读写速度

在Ubuntu下,可以使用hdparm、dd和fio等工具来测试硬盘的读写速度。 开始之前,先使用sudo fdisk -l命令来列出系统中所有的硬盘和分区: 1.使用hdparm测试硬盘读取速度: 安装hdparm: sudo apt-get install hdparm 通…

C++17中utf-8 character literal的使用

一个形如42的值被称作字面值常量(literal),这样的值一望而知。每个字面值常量都对应一种数据类型,字面值常量的形式和值决定了它的数据类型。 由单引号括起来的一个字符称为char型字面值,双引号括起来的零个或多个字符则构成字符串型字面值。 字符串字面…

9.QT 三目运算符

上面引出两个新的概念: 左值:能被赋值的就是左值。 右值:不能被赋值的就是右值。

基於ranger,kerberos,hadoop ha 配置hvie多用戶

基於ranger,kerberos,hadoop ha 配置hvie多用戶 hive多用戶權限管理一、hive的管理員用戶二、hive配置普通用戶1.添加用戶2.配置kerberos2.1 创建主体2.2 生成keytab文件2.3 修改keytab文件所有者(可做可不做) 3. 配置windows hive多用戶權限管理 一、h…

English Learning - L3 综合练习 8 TED-Living Beyond the Limits 2023.06.21 周三

English Learning - L3 综合练习 8 TED-Living Beyond the Limits 2023.06.21 周三 句 1句 2扩展 句 3句 4句 5句 6句 7扩展 random 句 8扩展 句 9句 10句 11句 12句 13句 14句 15句 16句 17句 18句 19句 20句 21句 22句 23 句 1 Four months later I was back up on a snowbo…

SVN使用步骤

1.基本操作 2.提交之间看一下变更内容 3.显示日志 是查看所有提交的记录4.撤销和恢复操作 撤销本地修改 或者点击提交的时候 还原 把修改的撤销掉 第二种情况,内容已经提交上去了点击提交日志 进行操作 只是撤销了本地 接着还需要继续提交到服务端 第三种情况 我们需要恢…

Linux系统之安装showdoc文档工具

Linux系统之部署showdoc文档工具 一、showdoc介绍1.1 showdoc简介1.2 showdoc功能 二、本地环境介绍2.1 本地环境规划2.2 本次实践介绍 三、检查本地环境3.1 检查本地操作系统版本3.2 检查系统内核版本3.3 检查本地yum仓库状态 四、安装httpd服务4.1 安装httpd4.2 启动httpd服务…

用Visual C++写出你第一个Windows程序

我是荔园微风,作为一名在IT界整整25年的老兵,今天来看看如何用Visual C写出你第一个Windows程序。 与其看很多Windows的书,不如先自己动手写一个Windows程序。由于Windows程序的特有机制,不建议去写那种简单的HELLO WORLD&#x…

iOS 制作私有库framework + 图片资源的使用

1. 库的分类 开源库:公开源代码,能看到具体实现** 闭源库**:不公开源代码,是经过编译后的二进制文件,看不到具体实现;其中包括:静态库和动态库 2. 开源库的制作 我了解的开源库的制作&#xff0…

Python基础篇(一):如何使用PyCharm创建第一个Python项目(包含tools)

如何使用PyCharm创建第一个Python项目 前言1.创建Python项目2. 创建第一个python文件3. 编写运行第一个python程序4. 关于此工具的相关使用 前言 环境版本Python3.11.4PyCharm2023.1.2OSwindows10 PyCharm是一款由JetBrains开发的强大的Python集成开发环境(IDE&am…

单个springboot整合rabbitmq

一、rabbitmq的搭建 centos7搭建rabbitmq:centos7安装rabbitmq_java-zh的博客-CSDN博客 二、在什么情况下选择rabbitMQ 常见的四种MQ比较 特 性ActiveMQRabbitMQRocketMQKafka语言JavaErlangJavaScala单机吞吐万万十万十万时效性msusmsms(以内)可用性高(主从架构…

模拟电路系列分享-复杂阻容电路的频响

目录 概要 整体架构流程 技术名词解释 技术细节 1.基本变形 2.单元串联的粗略计算 3.推广结论 小结 概要 在基本单元电路的基础上,熟悉一些常见的变形电路,学会判断是高通还是低通,快速计算出截止频率是多少,对求解复杂电路的频率…