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

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.rhkb.cn/news/457638.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【2024最新】渗透测试工具大全(超详细),收藏这一篇就够了!

所有工具仅能在取得足够合法授权的企业安全建设中使用&#xff0c;在使用所有工具过程中&#xff0c;您应确保自己所有行为符合当地的法律法规。如您在使用所有工具的过程中存在任何非法行为&#xff0c;您将自行承担所有后果&#xff0c;所有工具所有开发者和所有贡献者不承担…

eks节点的网络策略配置机制解析

参考链接 vpc-cni网络策略最佳实践&#xff0c;https://aws.github.io/aws-eks-best-practices/security/docs/network/#additional-resourcesvpc cni网络策略faq&#xff0c;https://github.com/aws/amazon-vpc-cni-k8s/blob/0703d03dec8afb8f83a7ff0c9d5eb5cc3363026e/docs/…

IP数据报的 分片与组装技术 深度解析

&#x1f351;个人主页&#xff1a;Jupiter. &#x1f680; 所属专栏&#xff1a;计算机网络高效通关之路 欢迎大家点赞收藏评论&#x1f60a; 目录 IP 分片和组装分片与组装的过程分片组装 分片与组装过程的示意图分片组装过程 IP 分片和组装 16 位标识(id): 唯一的标识主机发…

Redis 事务 总结

前言 相关系列 《Redis & 目录》&#xff08;持续更新&#xff09;《Redis & 事务 & 源码》&#xff08;学习过程/多有漏误/仅作参考/不再更新&#xff09;《Redis & 事务 & 总结》&#xff08;学习总结/最新最准/持续更新&#xff09;《Redis & 事务…

自旋锁原理及基于原子引用手写自旋锁

什么是自旋锁 自旋锁&#xff08;Spinlock&#xff09;是一种用于多线程同步的机制&#xff0c;在尝试获取锁时&#xff0c;如果锁已经被其他线程持有&#xff0c;则当前线程不会立即被阻塞&#xff0c;而是会进入一个循环中反复尝试获取锁&#xff0c;直到成功为止。这种机制通…

探索CRM功能:六个解决方案助力企业发展

在当前竞争激烈的市场环境中&#xff0c;企业面临着客户关系管理的诸多挑战&#xff0c;CRM&#xff08;客户关系管理&#xff09;系统能够有效解决客户数据孤岛、提升客户互动效率、增强销售预测准确性等问题。通过整合客户信息和优化业务流程&#xff0c;CRM帮助企业实现更高…

解决JeecgBoot微服务通过Gateway访问Swagger资源出现“Knife4j文档请求异常”

1.问题描述 基于jeecgboot单体版本,参照官方推荐的纯微服务项目拆分指南,对jeecgboot项目进行微服务拆分,将gateway和system模块启动成功后,通过gateway访问访问Swagger接口文档,出现“Knife4j文档请求异常”,如下图: 2.问题定位: 1.浏览器F12打开控制台,查看异常请…

Kafka-Eagle(可视化监控平台)安装教程

Kafka Eagle 1. Install Mysql Kafka-Eagle 的安装依赖于 MySQL&#xff0c;MySQL 主要用来存储可视化展示的数据。 2.Kafka 环境准备 调整Kafka内存占用等参数&#xff0c;暴露JMX JMX(Java Management Extensions)是一个为应用程序植入管理功能的框架。JMX是一套标准的代理和…

在GeoTools中的Shapefile属性表读取效率之Shp与Dbf对比

目录 前言 一、POI测试数据简介 1、选用的POI数据 2、关于数据的属性数据 二、属性数据读取的两种方式实现 1、基于DbaseFileReader的读取 2、基于SimpleFeatureSource的读取 三、实际运行对比 1、内存和CPU占用情况 2、运行耗时情况 四、总结 前言 众所周知&#x…

《向量数据库指南》——text-embedding-3-large与Mlivus Cloud打造语义搜索新纪元

使用text-embedding-3-large生成向量并将向量插入Mlivus Cloud实现高效语义搜索的深度解析与实战操作 在数字化时代,数据的处理和存储方式正在经历前所未有的变革。特别是随着大数据和人工智能技术的快速发展,向量数据库作为一种新型的数据存储和查询方式,正逐渐受到越来越…

系统架构设计师教程 第2章 2.6 计算机语言 笔记

2.6计算机语言 ★★★★☆ 2.6.1计算机语言的组成 计算机语言 (Computer Language) 是指用于人与计算机之间交流的一种语言&#xff0c;是人与计算机之间传递信息的媒介。 计算机语言主要由一套指令组成&#xff0c;指令一般包括表达式、流程控制和集合三大部分内容。 表达…

Selenium爬虫技术:如何模拟鼠标悬停抓取动态内容

介绍 在当今数据驱动的世界中&#xff0c;抓取动态网页内容变得越来越重要&#xff0c;尤其是像抖音这样的社交平台&#xff0c;动态加载的评论等内容需要通过特定的方式来获取。传统的静态爬虫方法难以处理这些由JavaScript生成的动态内容&#xff0c;Selenium爬虫技术则是一…

测试造数,excel转insert语句

目录 excel转sql的insert语句一、背景二、直接上代码 excel转sql的insert语句 一、背景 在实际测试工作中&#xff0c;需要频繁地进行测试造数并插入数据库验证&#xff0c;常规的手写sql语句过于浪费时间&#xff0c;为此简单写个脚本&#xff0c;通过excel来造数&#xff0…

Flink CDC系列之:调研应用Flink CDC将 ELT 从 MySQL 流式传输到 StarRocks方案

Flink CDC系列之&#xff1a;调研应用Flink CDC将 ELT 从 MySQL 流式传输到 StarRocks方案 准备准备 Flink Standalone 集群准备 docker compose为 MySQL 准备记录使用 Flink CDC CLI 提交作业 同步架构和数据更改路由变更清理 本教程将展示如何使用 Flink CDC 快速构建从 MySQ…

Rust 力扣 - 1. 两数相加

文章目录 题目描述题解思路题解代码题目链接 题目描述 题解思路 我们使用一个全局的备忘录&#xff0c;然后我们遍历数组&#xff0c;如果当前元素在备忘录里面找到了&#xff0c;就返回备忘录里面记录的下标和当前下标记录&#xff0c;没找到就把当前元素匹配的元素和当前元素…

DEVOPS: 容器与虚拟化与云原生

概述 传统虚拟机&#xff0c;利用 hypervisor&#xff0c;模拟出独立的硬件和系统&#xff0c;在此之上创建应用虚拟机是一个主机模拟出多个主机虚拟机需要先拥有独立的系统docker 是把应用及配套环境独立打包成一个单位docker 是在主机系统中建立多个应用及配套环境docker 是…

【WiFi7】 支持wifi7的手机

数据来源 Smartphones with WiFi 7 - list of all latest phones 2024 Motorola Moto X50 Ultra 6.7" 1220x2712 Snapdragon 8s Gen 3 16GB RAM 1024 GB 4500 mAh a/b/g/n/ac/6e/7 Sony Xperia 1 VI 6.5" 1080x2340 Snapdragon 8 Gen 3 12GB RAM 512 G…

基于JAVASE的题

字符集合 描述&#xff1a; 每组数据输入一个字符串&#xff0c;字符串最大长度为100&#xff0c;且只包含字母&#xff0c;不可能为空串&#xff0c;区分大小写。 每组数据一行&#xff0c;按字符串原有的字符顺序&#xff0c;输出字符集合&#xff0c;记重复出现并靠后的字…

【数学二】多元函数积分学-重积分-二重积分定义、性质、计算

考试要求 1、了解多元函数的概念&#xff0c;了解二元函数的几何意义. 2、了解二元函数的极限与连续的概念&#xff0c;了解有界闭区域上二元连续函数的性质. 3、了解多元函数偏导数与全微分的概念&#xff0c;会求多元复合函数一阶、二阶偏导数&#xff0c;会求全微分&#x…

以 6502 为例讲讲怎么阅读 CPU 电路图

开篇 你是否曾对 CPU 的工作原理充满好奇&#xff0c;以及简单的晶体管又是如何组成逻辑门&#xff0c;进而构建出复杂的逻辑电路实现&#xff1f;本文将以知名的 6502 CPU 的电路图为例&#xff0c;介绍如何阅读 CPU 电路图&#xff0c;并向你演示如何从晶体管电路还原出逻辑…