网络原理之 TCP解释超详细!!!

news2024/10/27 22:55:10

TCP
有连接的
可靠传输
面向字节流
全双工

其中最核心的是可靠传输
那么 TCP 如何使用可靠传输的 ???

我们尽可能传过去, 如果传不过去,发送方至少知道自己没传过去, 所以在于接收方, 收到或者没有收到, 都会有应答的操作

1. 确认应答

实现可靠性最核心的机制!!!

引出

举个发短信的例子
在这里插入图片描述

但是在网络上会经常出现后发先至的情况, 如下

在这里插入图片描述
如图我先收到了滚, 再收到了没问题, 这就会导致数据排序出现问题

所以为了解决上述的问题, 我们就需要针对消息进行编个号, 给发出的消息分配序号, 同时给出应答报文, 给出 “确认序号”
在这里插入图片描述
TCP 对每个字节的数据都进行了编号, 即序列号

TCP是对每个字节都去编号, 从前往后, 将每个字节都分配一个编号

在这里插入图片描述

确认序号的发送规则!!!

和发送方的序号无关, 而是去发送方发过来的所有数据, 最后一个字节的下一个字节的序号
在这里插入图片描述

确认序号1001, 如上图的含义

  • < 1001 的数据, 我已经接收到了
  • 我想要从1001开始的数据

接收方可以通过 ack 的确认序号, 告诉发送方哪些数据已经收到了

TCP 序号还有其他的重要用途

对 TCP 来说, 还承担了整队的任务

  • 每个 TCP 会有一个接收缓冲区 (一块内核的内存空间)

  • 每个 socket 都有自己的一份缓冲区, 可以根据序号进行整队, 当应用程序读数据的时候, 读到的一定是有序的

2. 超时重传

引出

如果没有什么特殊情况, 就可以直接确认应答

但是有时候会出现丢包, 这也是网络中非常正常的现象

在这里插入图片描述

  • 网络上有非常多的节点(路由器和交换机), 如果任意一个节点出现了问题, 都可能会出现丢包

  • 由于每个设备都要承当很多的转发任务, 转发能力都是由上限的

  • 某刻, 某个设备的流量达到了最高峰, 可能会引起部分数据丢失, 产生丢包

如果产生了丢包, 接收方自然而然就收不到数据, 也就不会返回 ack

发送方迟迟拿不到应答报文, 等待一小段时间后, 还是没有收到应答报文, 发送方就认为刚才数据丢包了, 就会重新发送一遍

发送方对丢包的判定

发送方对丢包的判定, 一定时间内, 没有收到 ack

  1. 数据直接丢了, 接收方并没有收到, 自然不会发 ack
  2. 接收方收到了数据, 但是发送的 ack 丢了

这两种情况都只能重传, 发送方是无法区别这两种情况的

在这里插入图片描述
在这里插入图片描述
可以根据以上两张图进行体会一下

在第二种情况中, 虽然会收到重复的数据, 但是TCP 会帮我们处理这个问题, 在接收缓冲区帮我们进行去重操作

疑问

重传的数据有没有可能又丢了呢???

如果发送连续丢包的话, 说明网络大概率出现了故障了

  1. TCP 针对 多个包丢失, 会继续超时重传 但是每丢包一次, 等待时间都会变长(重传的频率变低了), TCP 觉得重传估计也没用直接摆烂
  2. 如果连续多次重传, 都无法得到 ack 的话, 此时 TCP 会进行尝试重置连接(尝试重连) 尝试重连也失败, TCP 会直接关闭, 放弃网络通信

超时重传, 确认应答是 TCP 可靠性的两个基石

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

TCP 建立连接: 三次握手
TCP 断开连接: 四次挥手

混淆

TCP 如何实现可靠性???
确认应答 + 超时重传

以上的两个过程和可靠性, 仅仅只有一点关系而已

三次握手

握手 (handshake) 指的是通信双方, 进行一次网络交互
相当于 客户端 和 服务器 之间, 通过三次交互, 建立了连接关系 -> 记录双方的信息

syn 称作同步报文段 意思时一方向另一方, 申请建立连接

类比例子: 表白

小A 向一个女生表白: 你愿意做我的唯一吗 (发送 syn 报文)

女生返回一个应答, ack (我愿意)

女生: 你也愿意做我的唯一吗 (发送 syn 报文)

我也返回一个 ack (俺也一样)

双方都确认完自己的唯一, 此时建立起来关系 (连接建立完成)
在这里插入图片描述

以上过程内核自动完成, 应用程序无法干预

当连接完成后, 服务器 accept 把建立完成的连接从内核拿到应用程序里面

疑问

其实我们感觉到了四次交互的发送, 那为什么叫做三次握手呢???

因为把 syn 和 ack 拆开分别发送没有必要, 虽然可以, 同样也可以达成目的 但是效率不如一次发送

报文段解释

什么样的报文属于 syn 报文

在这里插入图片描述
如图所示, 我们可以发现这里有六个特殊的比特位

一般来说都是设置为 0 , 如果设置为 1 , 就代表有特殊的含义

其中第二位是 ack , 如果这一位为 1 , 代表这个 TCP 数据报是一个应答报文

其中第五位是 syn , 如果这一位是 1 , 代表这个 TCP 数据报是一个同步报文

如果一个 TCP 数据报, 第二位和第五位都为 1 , 说明当前这个报文时 syn + ack

疑问

三次握手起到了什么作用???

本质上三次握手属于投石问路, 互相验证客户端和服务器, 各自的发送能力与接收能力是否正常

例子

举例: 打游戏确认扬声器与麦克风

  • 比如小a 和小b 两个人打游戏, 需要互相确认一下各自的设备是否正常

  • 小a 先向小b 说到: 喵喵喵

  • 此时小b 听到了喵喵喵, 此时他就知道 小a 的麦克风正常; 小b 自己的扬声器正常

  • 小b 向小a 说到: 喵喵

  • 此时小a 听到了喵喵, 说明小b 收到了他的消息, 小a 知道 彼此的麦克风和扬声器都正常

  • 小a 向小b 说到: 喵

  • 此时小b 知道, 小b 自己的麦克风正常, 小a 的扬声器正常, 也知道彼此的麦克风和扬声器正常

此时就相当于确认客户端和服务器各自的发送能力和接收能力都很正常

这就是后续可靠传输的基础

四次挥手

通信双方各自给对方发送一个 FIN (结束报文), 再各自给对方返回 ACK

在这里插入图片描述
如上图所示

  • 建立连接, 一定是客户端主动发起的

  • 但是断开连接, 客户端和服务器都有可能先发起

疑问

为什么四次握手不将ack 和 fin 合并到一起呢???

  • ack 和 fin 有一定的概率合成一个, 一般情况下时不能合并的

  • 三次握手, ack 和 syn 是同一个时机触发的 (都是由内核来完成的)

  • 四次挥手, ack 和 fin 则是不同时机触发的

  • ack 是由内核完成的, 收到 fin 的时候第一时间返回 ack

  • fin 是由应用程序的代码来控制的, 在调用到 socket 的 close 方法的时候才触发 fin

在这里插入图片描述

服务器发现客户端断开连接后, 自己也进行 close 操作, 这个 close 触发了第二个 fin

这个 close 的执行时机取决于你代码怎么写, 可能是马上, 也可能隔很久

如果是立即的话, 趁着 ack 还没有发送, 就可以合并, 如果是隔很久再 close, 此时的 fin 只能单独进行发送

疑问

第二个 fin 客户端收不到嘛??? 第二个 ack 服务器收不到嘛???

假如, 在代码中, tcp 客户端, 没有显示调用 close , 当进程结束后, 自动会进行 close , 此时就会触发 fin, 此时客户端虽然进程结束了, 但是 tcp 连接还在 (由内核维护)
进程结束了, 但是内核会继续把 tcp 连接维护, 直到四次挥手完成, 服务器同理.

在这里插入图片描述
当此 fin 位为 1 时, 就是结束报文

滑动窗口

TCP 不仅要保持可靠连接, 还要保证效率.

在这里插入图片描述

如果按照如图, A 就会花大量时间去等待 ACK
所以想要提高效率, 需要缩短等待时间, 所以采用批量发送数据
一次发送多条数据, 一次等待多个 ack
在这里插入图片描述
这里就是批量发送四条数据, 发完后统一等待 ack
每收到一个 ack 就立刻发送下一条(不是收到 4 个 ack 再发送下一组)
上述传输过程, 称作滑动窗口

其中的批量发送, 并不是无限发送, 是发送到一定的程度后需要等待 ack
我们把批量等待数据的数量, 就称作滑动窗口的大小

在这里插入图片描述

如图所示, 批量发送了四条数据, 等待 4 个 ack, 白色区域表示等待的窗口

当收到 2001 这个 ack 代表 1001- 2000 这个数据得到确认, 此时发送下一个数据 5001 - 6000

疑问

如果批量传输过程中发送丢包怎么办

在这里插入图片描述

如图所示, 图中一半的 ack 都丢了

但是对于可靠性没有任何影响

确认序号的含义就是, 该序号之前的数据都收到了, 也就是后一个 ack , 可以包括前一个 ack 的意思

  • 当收到 2001 这个 ack 的时候
  • 此时发送方就知道, 2001 之前的数据都收到了
  • 1 - 1000 这个数据也收到了
  • 所以 1001 这个 ack 丢了也无所谓

假设最后一个丢了, 直接就超时重传即可

在这里插入图片描述
如图所示

  • 由于发送的时候, 1001 - 2000 这个数据丢失了

  • 所以接收方仍然索取1001, 不会说收到 2001 - 3000 就返回 3001

  • B 向 A 反复索要 1001 的数据

  • A 这里收到了连续好几个 1001 后, 就知道 1001 应该是丢了, A 就重传了 1001 - 2000 的数据

  • 当 B 收到这个数据后, 返回的 ack 确认序号时 7001 ,不是 2001

  • 由于 2001 - 7000 这些数据, B 都已经收到过了, 所以直接返回 7001

上述的重传过程, 没有任何的冗余操作

只有丢了数据才会重传

不丢数据不会重传

这个重传过程也被称作快速重传

在程序中接收到的数据是先放到接收缓冲区里


然后应用程序可以通过 socket 里的 inputStream 来读取数据, 代码中读到的数据可以在接收缓冲区删除掉

流量控制 (也是保证可靠性的机制)

为了防止滑动窗口过大, 导致发的太快, 如果瞬间将接收方的接收缓冲区给塞满了, 接下来如果继续发送, 此时数据就会丢包, 这种情况就会得不偿失

流量控制, 本质上就是限制一下发送方的速度, 让发送方慢一点, 甚至阻塞一下

在这里插入图片描述
当 ack 为 1 的时候, ack 报文, 此时窗口大小字段就会生效, 这里的值就是建议发送方发送窗口的大小

疑问

接收方是如何计算窗口大小的呢???

直接拿接收缓冲区的剩余空间, 作为窗口大小

如下图来演示一下过程
在这里插入图片描述

在这里插入图片描述

当然, 上述过程只把返回的窗口大小, 当作实际窗口了

实际上会有一点出入 (拥塞控制)

发送发窗口大小受到 拥塞控制 和 流量控制 的限制

拥塞控制

发送发窗口大小受到 拥塞控制 和 流量控制 的限制

  • 流量控制: 衡量了接收方的处理能力
  • 拥塞控制: 衡量了传输路径的处理能力

在这里插入图片描述

如果路径上, 任何一个设备, 处理能力遭遇到了瓶颈期, 都会对整体的传输效率产生明显的影响 (木桶效应)

拥塞控制, 就是衡量中间节点的传输能力

通过实验的方式找到一个最适合的发送频率

  • 开始, 按照一个小的速率发送

  • 如果没有发生丢包, 就提高速率 (扩大窗口大小)

  • 如果出现丢包, 直接把速率调小

  • 实际窗口的大小 = min(拥塞窗口, 流控窗口)

在这里插入图片描述

在这里插入图片描述

延时应答

为了提高传输效率

ACK 要发送的时候, 不是立即就发送, 而是稍微磨蹭一会再发送

TCP 中决定传输效率的关键元素窗口大小

类似一个生产者消费者模型

在这里插入图片描述

  • 立即返回一个 ACK , 此时 ACK 里面有一个窗口大小, 设为 n

  • 如果稍微等一下, 再返回 ACK , 此时 ACK 里的窗口大小很大概率会比 n 要大

  • 因为等着一小会, 应用程序从接收缓冲区里, 又可以消费掉一批数据, 空间变大了

  • 延时应答的效果, 通过延时, 让接收方多处理一些数据, 反馈的窗口大小就会更大一点

  • 发送发的发生效率也会提高 (同时让接收方能处理的过来这些数据)

捎带应答

基于延时应答

客户端服务器的通信模型, 通常是 “一问一答” 这种模式
在这里插入图片描述
如上图, 一般来说 A 发送一个请求后, B 要返回一个 ack , 但是我们通过捎带应答, 稍微等一会, 将响应的数据和 ack 一起发送, 合成同一个数据报一起发送, 效率更高

面向字节流 => 粘包问题

在这里插入图片描述
比如以上的消息
小A 接收到的消息是
在这里插入图片描述
从小A 的视角上来看, 并不知道哪一句是完整的, 难以区分是哪一句

引出粘包问题

一句话就相当于一个 “应用层数据报”

当 A 给 B 连续发了多个应用层数据报后, 这些数据就都累积到了 B 的接收缓冲区中,紧紧挨在一起
此时 B 的应用程序在读数据时, 就很难区分从哪到哪是一个完整的应用层数据报 (要和确认应答的序号区分开, 这两个是不相同的, 此时相当于已经到了应用层, 序号只能保证数据包的传输顺序是正确的, 你并不知道从哪里断句, 哪里属于一段话)

解决方法

定义分隔符: 比如和 小B 约定每说一句话都以 . 结尾
约定长度: 比如约定前四个字节, 表示整个数据报的长度

异常处理

  1. 进程关闭 / 进程奔溃

进程没了, socket 文件也被关闭, 但是连接还在, 仍然可以进行四次挥手, 由操作系统来替你进行

  1. 主机关机 (正常流程关机)
  • 先杀死所有的用户进程
  • 也会触发四次挥手, 如果挥完更好. 如果没挥完, 例如, 对方的 fin 发过来了, 我们还没来得及 ack 就关机了
  • 此时对端就会重新传输 fin , 重传几次后发现还是没有 ack , 尝试重新连接 , 还不可以, 直接释放连接
  1. 主机掉电(直接把主机的电源插头拔了)
    机器瞬间关机, 来不及进行任何的挥手操作
    分为两种情况
  2. 对端是发送方
    对端就会收不到 ack -> 超时重传 -> 重置连接 -> 释放连接
  3. 对端是接收方
    对端无法知道, 你是没来得及发送新的数据, 还是已经没了
    但是 TCP 内置心跳包的保活机制

心跳包

虽然对端是接收方, 对端会定期给我们发送一个心跳包 (ping), 我们会返回一个 (pong)
  • 如果每个 ping 都有一个及时的 pong, 说明当前对端的状态良好, 如果 ping 过去之后, 没有 pong , 没心跳了, 大概率是挂掉了
  • 心跳包没那么严格, 比如连续五次 ping 没有 pong 才是连接异常
  1. 网线断开同上

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

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

相关文章

一种解决Leaflet中Divicon城市气温标注空间重叠的办法

目录 前言 一、一些解决办法 1、marker的聚类 2、使用leaflet-canvas-label 3、使用Zoom和样式控制 二、基于rbush和Leaflet.LayerGroup.Collision的解决办法 1、关于rbush 2、Leaflet.LayerGroup.Collision.js 三、解决标签重叠的具体实现 1、添加元数据 2、添加到…

理解OAuth2与用户账户与授权UAA的关系

目录 关于OAuth2OAuth2的核心组件授权流程授权模式使用场景优点与缺点 关于UAA技术解释 UAA与OAuth2的关系 关于OAuth2 ‌‌OAuth2&#xff08;开放授权2.0&#xff09;是一个开放标准&#xff0c;用于授权第三方应用程序访问用户资源&#xff0c;而无需共享用户的用户名和密码…

c语言中值调用(call by value)方式和引用调用(call by reference)

在C语言中参数传递主要有两种方式&#xff1a;通过值调用&#xff08;call by value&#xff09;和通过引用调用&#xff08;call by reference&#xff09;。 通过值调用&#xff08;Call by Value&#xff09; 说明&#xff1a;当使用值调用时&#xff0c;函数接收到的是参数…

(三)第一个Qt程序“Qt版本的HelloWorld”

一、随记 我们在学习编程语言的时候&#xff0c;各种讲解编程语言的书籍中通常都会以一个非常经典的“HelloWorld”程序展开详细讲解。程序虽然简短&#xff0c;但是“麻雀虽小&#xff0c;五脏俱全”&#xff0c;但是却非常适合用来熟悉程序结构、规范&#xff0c;快速形成对编…

Linux--学习笔记

第一章、简单使用Linux 1. Linux系统基本概念 多用户的系统&#xff1a;允许同时有很多个用户登录系统&#xff0c;使用系统里的资源多任务的系统&#xff1a;允许同时执行多个任务严格区分大小写&#xff1a;命令&#xff0c;选项&#xff0c;参数&#xff0c;文件名&#x…

从零实现数据结构:一文搞定所有排序!(下集)

1.快速排序 思路框架&#xff1a; 在有了前面冒泡选择插入希尔排序之后&#xff0c;人们就在想能不能再快一点&#xff0c;我们知道排序算法说人话就是把大的往后放小的往前放&#xff0c;问题就在于如何更快的把大的挪到数组队尾小的挪到数组前面。这里我们先总结一下上集前…

jenkins 自动化部署Springboot 项目

一、安装docker 1.更新yum命令 yum -y update2.查看机器有残留的docker服务&#xff0c;有就卸载干净 查看docker 服务 rpm -qa |grep docker卸载docker sudo yum remove docker-ce docker-ce-cli containerd.io sudo rm -rf /var/lib/docker sudo rm -rf /var/lib/contai…

算法的学习笔记—二叉树的深度(牛客JZ55)

&#x1f600;前言 在二叉树的相关操作中&#xff0c;计算树的深度是一个非常基础但十分重要的操作。本文将详细解析如何计算一棵二叉树的深度&#xff0c;并通过代码实现来展示具体的解决方案。 &#x1f3e0;个人主页&#xff1a;尘觉主页 文章目录 &#x1f49d;二叉树的深度…

了解 .NET 8 中的定时任务或后台服务:IHostedService 和 BackgroundService

IHostedService.NET 8 引入了使用和管理后台任务的强大功能BackgroundService。这些服务使长时间运行的操作&#xff08;例如计划任务、后台处理和定期维护任务&#xff09;可以无缝集成到您的应用程序中。本文探讨了这些新功能&#xff0c;并提供了实际示例来帮助您入门。您可…

HarmonyOS开发 - 本地持久化之实现LocalStorage实例

用户首选项为应用提供Key-Value键值型的数据处理能力&#xff0c;支持应用持久化轻量级数据&#xff0c;并对其修改和查询。数据存储形式为键值对&#xff0c;键的类型为字符串型&#xff0c;值的存储数据类型包括数字型、字符型、布尔型以及这3种类型的数组类型。 说明&#x…

同步电机不同电流参考方向下的功率计算

同步电机的功率计算有时候会看见两种表达方式&#xff1a; 当以发电机惯例&#xff0c;即电流方向输出时&#xff0c;功率计算式为&#xff1a; { P s 3 2 ( u s d i s d u s q i s q ) Q s 3 2 ( u s q i s d − u s d i s q ) \left\{\begin{array}{l} P_{\mathrm{s}}\fr…

PostgreSQL(十三)pgcrypto 扩展实现 AES、PGP 加密,并自定义存储过程

目录 一、pgcrypto 简介1.1 安装 pgcrypto 扩展1.2 pgcrypto 包含的函数 二、用法①&#xff1a;对称加密&#xff08;使用 AES、Blowfish 算法&#xff09;2.1 密钥2.2 密钥偏移量 三、用法②&#xff1a;PGP加解密3.1 什么是PGP算法&#xff1f;3.2 使用 GPG 生成密钥对3.3 列…

【AI大模型】深入解析 存储和展示地理数据(.kmz)文件格式:结构、应用与项目实战

文章目录 1. 引言2. 什么是 .kmz 文件&#xff1f;2.1 .kmz 文件的定义与用途2.2 .kmz 与 .kml 的关系2.3 常见的 .kmz 文件使用场景 3. .kmz 文件的内部结构3.1 .kmz 文件的压缩格式3.2 解压缩 .kmz 文件的方法3.3 .kmz 文件的典型内容3.4 .kml 文件的结构与主要元素介绍 4. 深…

豆包MarsCode Agent 登顶 SWE-bench Lite 评测集

大语言模型&#xff08;LLM&#xff09;能力正在迅速提升&#xff0c;对包括软件工程在内的诸多行业产生了深远影响。GPT-4o、Claude3.5 等 LLM 已经逐步展现出胜任复杂任务的能力&#xff0c;例如文本总结、智能客服、代码生成&#xff0c;甚至能够分析和解决数学问题。在这一…

为什么在网络中不能直接传输数据

为什么在网络中不能直接传输数据 原因 在网络中不能直接传输原始数据形式&#xff0c;主要有以下几方面原因&#xff1a; 数据表示的多样性&#xff1a;不同的计算机系统、编程语言和应用程序对数据的表示方式可能各不相同。例如&#xff0c;整数在不同的编程语言中可能有不同…

了解Java开发中的会话层

在现代Web应用开发中&#xff0c;会话管理是一个至关重要的概念。它涉及到如何在客户端和服务器之间保持用户状态信息&#xff0c;从而提供个性化、连续的用户体验。Java作为一种广泛使用的编程语言&#xff0c;在Web开发中扮演着重要角色&#xff0c;特别是在企业级应用中。了…

基于neo4j的课程资源生成性知识图谱

你是不是还在为毕业设计苦恼&#xff1f;又或者想在课堂中进行知识的高效管理&#xff1f;今天给大家分享一个你一定会感兴趣的技术项目——基于Neo4j的课程资源生成性知识图谱&#xff01;&#x1f4a1; 这套系统通过知识图谱的形式&#xff0c;将课程资源、知识点和学习路径…

一文掌握异步web框架FastAPI(五)-- 中间件(测试环境、访问速率限制、请求体解析、自定义认证、重试机制、请求频率统计、路径重写)

接上篇:一文掌握异步web框架FastAPI(四)-CSDN博客 目录 七、中间件 15、测试环境中间件 16、访问速率限制中间件,即限制每个IP特定时间内的请求数(基于内存,生产上要使用数据库) 1)限制单ip访问速率 2)增加限制单ip并发(跟上面的一样,也是限制每个IP特定时间内的请…

vue2结合echarts实现数据排名列表——前端柱状进度条排行榜

写在前面&#xff0c;博主是个在北京打拼的码农&#xff0c;工作多年做过各类项目&#xff0c;最近心血来潮在这儿写点东西&#xff0c;欢迎大家多多指教。 数据排名列表——图表开发&#xff0c;动态柱状图表&#xff0c;排名图 UI 直接搜到类似在线代码&#xff08;数据列表…

事务的原理、MVCC的原理

事务特性 数据库事务具有以下四个基本特性&#xff0c;通常被称为 ACID 特性&#xff1a; 原子性&#xff08;Atomicity&#xff09;&#xff1a;事务被视为不可分割的最小工作单元&#xff0c;要么全部执行成功&#xff0c;要么全部失败回滚。这意味着如果事务执行过程中发生…