TCP的可靠机制

news2024/11/14 15:36:41

TCP的可靠机制

前言

要了解TCP的可靠机制,我们必须要先熟悉TCP的报文,在这篇文章中有详细介绍TCP的报文 :

并且确认应答机制也在该文章中提到,所以这篇文章就不会再介绍确认应答了。

超时重传

我们都知道,报文在网络中传输是有可能丢包的。如果丢包了,那么TCP又该如何处理?

首先我们要分为2种情况,1种情况是数据丢了,一种情况是服务器发的应答丢了。

情况1.数据丢了

在这里插入图片描述

这个问题很好解决,因为TCP有确认应答机制。收到了一条数据那么就必须要发送一个应答告诉对方收到了这条报文。如果没有收到,那么发送数据发会认为自己的数据并没有被收到,此时间隔一段时间(超时时间)进行报文重传。

情况2.应答丢了

这种情况就是数据已经到达了对端,但是对端给的应答丢了。

在这里插入图片描述

这情况发送数据方依旧在超时时间后重新发送报文。因为无论是应答丢了还是数据丢了,发送方是不知道的。而当应答丢了的时候,又发送了一则数据。那么对端就收到了重复的报文,此时对端会通过32位序列号对报文进行排序,如果序列号相同的则会进行去重。

超时时间

知道了在数据或者应答丢失的情况下,发送方会隔一段时间进行重传。 那么这 一段时间 是多久呢?

如果超时时间设置太短,那么可能会发送重复的包。

如果超时时间设置太长,那么又可能造成效率问题。

并且网络中的环境也是即使变化的。

所以TCP为了保证无论在任何坏境下都能比较高性能的通信,会动态计算这个最大超时时间。

在Linux中,超时以500ms为一个单位进行控制,每次判定超时重发的超时时间都是以500ms的整数倍。

第一次重发的时间是500ms ,如果第一次重发后没有得到回应,那么第二次就会第 2 * 500ms进行重发。第三次则是 4 * 500ms… 直到到达一定次数时,TCP认为网络或者对端主机出现异常,强制关闭连接。

连接管理

TCP是面向连接的,TCP每次与一个客户端连接成功,那么就会创建一个连接。那么这个连接要不要管理?要!怎么管理?先描述,再组织。创建一个描述连接的结构体,由操作系统进行管理。也就是每一个连接都有自己对应的数据结构!每一个连接都占用着操作系统的一份资源!

上面说的连接建立成功之后的情况,那么如何建立连接?

三次握手

在正常情况下,TCP连接是要经过三次握手的过程。断开时要经历四次挥手过程。而三次握手过程必然是客户端先发起的,不存在有服务器去连接客户端的情况。你好比你访问了一个页面,那么访问请求肯定是先从你的浏览器发起的。因为服务器根本不知道你的IP和端口,只有你先发送报文过后,服务器才能获得你的IP + 端口。服务器和客户端是1 : N 的关系。

三次握手过程

1.客户端向服务器发送带有SYN的报文,并自己处于SYN_SENT状态

2.服务器收到了客户端发送的SYN报文,此时服务器处于SYN_RCVD状态,并向客户端发送SYN+ACK

3.客户端收到服务器发送的SYN+ACK报文,此时客户端建立连接成功,此时客户端处于ESTABUSHED状态,并向服务器发送ACK

4.服务器收到客户端建立连接成功后发送的ACK报文,知道了客户端建立连接成功,此时服务器处于ESTABUSHED状态

在这里插入图片描述

当到达第四步的时候!客户端与服务器之间的连接就已经建立好了!而accept函数是从底层获取连接,而不是建立连接的函数!

为什么是三次握手,而不能是一次,两次,或者四次?

先来说为什么不能是一次握手

如果是一次握手的话,客户端只要发送连接,服务器就认为连接成功了。那么客户端是不是可以同时发送大量的SYN连接请求,而服务器每收到一个连接请求就建立一个连接。因为每建立一个连接就要消耗一份系统资源,而客户端那边发起连接请求几乎没有成本。所以服务器最终会不会因为连接请求过多而导致崩溃呢?答案是会的!

而同时发送大量SYN连接请求这种行为,也被称为SYN洪水攻击

为什么不能是2次握手?

2次握手和1次握手的本质是一样的。只要客户端发送SYN,服务器就认为已经连接成功了!至于ACK,客户端压根可以不关心!2次握手照样可以通过SYN洪水攻击让服务器产生大量的连接最后导致服务器崩溃。而客户端这边几乎没有成本,因为只是仅仅发送一个SYN报文而已。

在这里插入图片描述

三次握手为什么又可以了呢?

一次握手和2次握手的本质是不清楚服务器和客户端的收发能力!

一次握手的时候,服务器知道客户端有发送数据的能力和自己有收数据的能力,但不知道自己发送数据的能力和客户端接收数据的能力

二次握手客户端知道服务器有收数据和发送数据的能力,服务器知道自己有收数据的能力,但不知道自己有发数据的能力

而三次握手,服务器和客户端都自己彼此的收数据和发送数据的能力。

在这里插入图片描述

并且我们可以看到,客户端在收到服务器发来的ACK+SYN后,就已经建立了连接!此时客户端再给服务器发送ACK,服务器收到ACK才开始建立连接。 这就意味着,客户端在服务器之前建立连接!也就说明了,客户端建立连接是有成本的!这样一来,客户端和服务器就都要维护等量的连接,一旦你客户端连接过多,对端也可以进行相应的判断处理。

TCP能保证安全吗?

很遗憾,不能。三次握手只能让一台主机和服务器承受同等的连接压力。但无法抑制多台主机的同时访问。假设有1W台主机,同一时间给你的2核2G服务器发送连接请求。那么你的服务器就同时来了1W个连接,最后因为超负荷饮恨被操作系统KILL掉。而这种攻击手段想必大家都听过,就是DDOS攻击

为什么不是四次握手?

三次握手可以做到的事情,为什么要四次握手呢?多一次握手就相当于要多发一条报文,而全世界那么多人每天都在使用网络。无论是四次握手,五次还是六次,都是对网络资源的一种浪费。就好比有两家小卖铺摆在你面前,同一样东西,一家只要1块钱,另一家要10块钱。肯定选1块钱的那家啊。人傻钱多当我没说=。=

四次挥手

建立连接时有三次握手,那么关闭连接也会有四次挥手(你拔电脑电源让电脑秒关机不算)。而四次挥手的过程和三次握手类似。只不过三次握手必须由客户端发起,而四次挥手无论是客户端还是服务器都可以发起。所以下面我们假设是客户端发起四次挥手。

四次挥手过程

1. 客户端关闭连接(close fd),状态变成FIN_WAIT_1 ,并向服务器发送携带FIN被置为1的报文

2. 服务器收到客户端的FIN报文,状态变为CLOSE_WAIT,并向客户端发送ACK确认。

3. 客户端收到ACK后,状态变为FIN_WAIT_2

4. 服务器端Close连接后,向客户端再次发送FIN报文,并状态被置为LAST_ACK

5. 客户端收到服务器发送的FIN,进入TIME_WAIT状态。并向服务器发送ACK

6. 服务器收到ACK,四次挥手过程结束

在这里插入图片描述

当我们的客户端断开连接时,也就是调用了close(fd),那么就会向服务器发送FIN,并把自己置为FIN_WAIT_1。此时的服务器处于CLOSE_WAIT状态。

CLOSE_WAIT

如果我们的服务器不进行close(fd)关闭文件描述符,那么就会造成该连接一直处于CLOSE_WAIT状态而无法释放。而客户端也因为没有收到服务器发来的FIN,一直处于FIN_WAIT_2状态。直到超时被关闭。

在这里插入图片描述

TIME_WAIT

当发起断开连接的那一端收到对端发来的FIN时,则会向对端发送一条ACK。自己处于TIME_WAIT状态,一般TIME_WAIT状态会持续2MSL(报文最大生存时间)。因为此时关闭连接端向对端发送的ACK是有可能丢包的,所以需要处于TIME_WAIT状态一段时间。如果ACK报文丢包了,则会进行重传。

在这里插入图片描述

所以这也就可以解释了,为什么我的服务器有时候不能立即重启。因为当服务器主动断开连接时,如果此时有客户端还没有关闭,那么服务器会处于TIME_WAIT状态,此时重启就会绑定出错,我们可以用地址复用的方法来解决。

滑动窗口

如果我们发送数据,在没有收到应答之前,是可能出现丢包的情况,如果丢包,就要超时重传。为了支持超时重传,我们是不是要把数据保存起来?保存在哪里呢? 保存在TCP的发送缓冲区

**这个发送缓冲区至少被分成三个区域,第一段区域是已经发送&&收到应答的数据,第二段区域是已经发送,但还没有收到应答的区域。第三段是数据尚未发送的区域。**当然还有第四段,空区域,新发送的数据会被拷贝到这段区域。

在这里插入图片描述

而中间那段已经发送但没有收到应答的区域,被称之为滑动窗口

1.如何看待滑动窗口?

发送缓冲区的本质就是一个数组,而滑动窗口则代表的一段区间,我们可以用win_start和win_end两个指针来表示这段区间。在这里插入图片描述

2.滑动窗口的开始大小是怎么设定的?之后怎么变化?

很简单,我们上面说了滑动窗口是win_start - win_end的区间。那么我们开始就把 win_start = 0,win_end = win_start + tcp_win(16位窗口大小的值)。之后无论滑动窗口怎么滑动,都必须保证在对方的接受能力范围之内。

**窗口的大小就等于对方的接受能力,也就是tcp_win16位窗口大小字段(不考虑网络拥塞的情况下)。 **

3.窗口一定会向右滑动吗?会向左滑动吗?

首先,滑动窗口左边的内容是已经发送并且收到应答了的,再次发送没有意义,所以滑动窗口不会向左滑动

滑动窗口大部分情况下是会向右滑动的,但是如果对方的接收能力为0呢?无法往对方发送数据,所以此时的滑动

窗口是不变的。所以滑动窗口可能向右滑动,也可能保持不变

4. 滑动窗口会一直不变吗?会变大吗?会变小吗?为什么?

滑动窗口可能会不变,但不可能一直不变!

会变大吗? 会! 当对端的上层突然把缓冲区数字拿走时,对端的接收能力大大提升,当发送端重新获得对方的窗口大小时。滑动窗口也会跟着变化,因为对方的接受能力变强,所以发送端的滑动窗口也会变大!

会变小吗?会!当对端的上层迟迟不拿数据,而发送端不断的发数据,那么win_start就会越来越大,而win_end却没有变,这也就意味滑动窗口在慢慢变小。直到最后对端的缓冲区被打满了,发送端的滑动窗口也会变为0。

5…收到应答确认的时候,如果不是最左侧发送的报文的确认,而是中间的,结尾的怎么办?要滑动吗?

这种时候我们要分两种情况,一种是应答丢了,数据没丢,一种是数据丢了。

应答丢了,数据没丢

如果是应答丢了,数据没丢的时候,没关系。因为TCP有32位确认序号。即使的前面的应答丢了,但是后面的应答的32位确认序号填的是后面数据的,那么发送数据方就知道确认序号之前的数据已经全部被对方收到了。

在这里插入图片描述

所以应答丢的情况,滑动窗口会照样滑动。

数据丢了

TCP是有32位序号的,在收到一批报文后会对报文进行排序。如果中间出现丢包的情况,那么确认序号就不能填收到的,而是丢包之前的那一个。假设现在收到4个报文 0 - 1000 , 1001 - 2000 , 3001 - 4000,而在对报文进行排序时发现中间的 2001 - 3000丢了,那么 3000之后的报文应答的确认序号只能填 2001 ,当对端连续收到3个2001时,就知道自己 2001 - 3000的报文丢包了。所以就会进行重传。

在这里插入图片描述

当收到好几个重复的确认序号时,发送端就知道自己之前的报文丢包了,所以会进行重传机制。而滑动窗口也只是滑到2001的位置。并且重新发送数据。

6. 滑动窗口会一直向后滑动吗?如果空间不够了怎么办?

从物理结构上看,滑动窗口是一个数组。但是从逻辑结构上看,滑动窗口是一个环形结构。我们可以通过 %数组的长度,来实现一个环形结构的数组。

流量控制

流量控制其实在上篇文章介绍16位窗口大小就已经提到过,通过16位窗口大小知道对方的接收能力。但这还不够,因为我们考虑到了对方的接收能力,但却没有考虑的网络的接收能力。如果网络当前坏境较差,发送大量数据会加重网络环境。那么此时只能按照网络能接收的能力来,而这一块我们会在下面拥塞控制中得到。所以滑动窗口的大小 = Min(对方接收能力,网络接收能力)

拥塞控制

前面我们一直在说客户端与服务端之间的可靠性。可是你有没有想过,无论是哪端发送数据,数据都是要在网络中传输的。如果网络出现问题了呢?如果网络因为大量报文而造成网络拥塞了呢?那么TCP也要有一种机制来保证在网络中传输的可靠性,这种机制就是拥塞控制

TCP如何判断网络拥塞

我们都了解当报文丢失时会触发超时重传。但这是少量报文丢失的情况,如果大量报文丢失的情况呢?这时候也要进行重传吗?答案是绝对不可行!因为此时网络可能已经出现问题了!本来就因为大量数据而造成网络拥塞,而你此时又重传大量的报文。要知道,全世界那么多主机,大部分都是使用的TCP协议。也就是说如果每台主机都去重传大量的报文,那么就会造成网络瘫痪。

举个例子:

当你们学校考试,假如考的是数据结构这门课。如果全班50人只有1-2个人挂科了,那么你会觉得这种情况是正常的。而如果只有1 - 2 个人没挂科,那么你们一定会认为这一定是老师的问题,老师出的题太难太偏。

所以TCP判断网络拥塞也是这样一个道理,当你发了1000个报文,丢失了3个报文。那么会认为是正常的丢包,进行超时重传。如果丢失的是999个报文,这时候就绝对不能进行重传了!因为这种情况肯定是网络发生拥塞,要进行拥塞控制。

TCP的慢启动机制

慢启动机制就是先发送少量数据探探路,摸清当前的网络状态,再决定按照多大的速度传输数据。

  • 引入一个概念,拥塞窗口(cwnd)
  • 发送刚开始的时候,拥塞窗口大小为1
  • 每收到一个ACK应答,拥塞窗口 + 1。相当于每次发送的报文 * 2
  • 每次发送数据包的时候,将拥塞窗口和对端发来的窗口大小作比较,取较小值作为实际发送的窗口

像上面这样的拥塞窗口速度,是指数级别的,刚开始很慢,但后面会非常快。所以我们要引入一个慢启动的阈值 ,这个阈值被称为ssthresh。

在这里插入图片描述

TCP刚开始启动的时候,阈值为滑动窗口的最大值。拥塞窗口则为1,此时拥塞窗口呈指数级增长,直到增长的阈值时呈线性增长。在线性增长过程中如果遇到了网络拥塞,则会进行乘法减小。把阈值更改为遇到网络拥塞时的一半,拥塞窗口从1开始继续慢启动。重复上面的步骤。

遇到网络拥塞时,是不能发送太多数据的,所以从1开始发送数据进行慢启动,阈值之前呈指数增长,阈值之后呈线性增长。前期的指数增长速度其实是比较慢的,可以有效的缓解网络的压力。而中后期网络恢复,又可以快速的恢复通信。因为指数增长后期非常的快,所以引入了阈值,超过阈值则进行线性增长。

当然,如果网络非常的好,而发送的数据又不多的话。拥塞窗口会一直缓慢增长,但这并不是大问题。因为实际的发送窗口是对端窗口大小和拥塞窗口的较小值。

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

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

相关文章

2024年【起重机司机(限桥式起重机)】最新解析及起重机司机(限桥式起重机)找解析

题库来源:安全生产模拟考试一点通公众号小程序 起重机司机(限桥式起重机)最新解析根据新起重机司机(限桥式起重机)考试大纲要求,安全生产模拟考试一点通将起重机司机(限桥式起重机)模拟考试试题进行汇编,组成一套起重机司机(限桥式起重机)全…

c++(模版)

目录 函数模板格式 函数模版原理 函数模板的实例化 模板参数的匹配原则 类模板 函数模板格式 template<typename T1, typename T2,......,typename Tn> 返回值类型 函数名(参数列表){} template<typename T> void Swap( T& left, T& right) { T te…

cesium的flyTo在飞行完成后渲染

viewer.camera.flyTo({}); 替换自己要渲染的labe img等 viewer.camera.flyTo({destination: Cesium.Cartesian3.fromDegrees(lon,lat,height), // 飞行目的地&#xff0c;视角高度duration: 3, // 飞行所用时间// 飞行完成后的事件complete: function() {viewer.camera.flyTo…

pytorch: cpu,cuda,tensorRt 推理对比学习

0&#xff1a;先看结果 针对resnet模型对图片做处理 原图结果 分别使用cpu&#xff0c;cuda&#xff0c;TensorRt做推理&#xff0c;所需要的时间对比 方法时间cpu13s594mscuda711mstensorRt 113ms 项目地址&#xff1a; GitHub - july1992/Pytorch-vily-study: vily 学…

KubeVirt虚拟机存储及网络卸载加速解决方案

1. 方案背景 1.1. KubeVirt介绍 随着云计算和容器技术的飞速发展&#xff0c;Kubernetes已成为业界公认的容器编排标准&#xff0c;为用户提供了强大、灵活且可扩展的平台来部署和管理各类应用。然而&#xff0c;在企业的实际应用中&#xff0c;仍有许多传统应用或遗留系统难…

电脑缺少directx怎么办?电脑dll修复详细教程!7种方法!

DLL&#xff08;动态链接库&#xff09;文件是Windows操作系统中非常重要的组成部分&#xff0c;它们包含了程序运行所需的代码和数据。然而&#xff0c;由于各种原因&#xff0c;如系统更新、软件卸载不当或病毒感染&#xff0c;DLL文件有时会丢失或损坏&#xff0c;导致程序无…

day18 Java流程控制——Scanner进阶使用

day18 Java流程控制——Scanner进阶使用 本章目录 day18 Java流程控制——Scanner进阶使用1. 什么是Scanner&#xff1f;2. Scanner进阶使用&#xff08;实例&#xff09;2.1 整数&小数的输入输出2.2 我们可以输入多个数字&#xff0c;并求其总和与平均数&#xff0c;每输入…

96年高中程序员年收入30万

互联网创业交流群&#xff0c;从昨天晚上8.1建军节开始建群&#xff0c;到今天中午已经突破200人了。 这里面有我的朋友&#xff0c;也有马总的朋友&#xff0c;当然不管是谁的朋友&#xff0c;进来了大家都是一家人。 以后在不违反原则的情况下&#xff0c;希望大家能和谐相…

建筑业数据挖掘:Scala爬虫在大数据分析中的作用

数据的挖掘和分析对于市场趋势预测、资源配置优化、风险管理等方面具有重要意义&#xff0c;特别是在建筑业这一传统行业中。Scala&#xff0c;作为一种强大的多范式编程语言&#xff0c;提供了丰富的库和框架&#xff0c;使其成为开发高效爬虫的理想选择。本文将探讨Scala爬虫…

《Cloud Native Data Center Networking》(云原生数据中心网络设计)读书笔记 -- 03 云原生网络操作系统

本章要回答的问题&#xff1a; 云原生网络操作系统的主要需求是什么?什么是 OpenFlow 和软件定义网络? 它们适用什么样的场景?网络解耦中网络操作系统有哪些可能的选择?这些模型与云原生 NOS 的需求相比是怎样的? 网络设备的新需求 云原生时代中网络设备需要满足以下要求…

揭秘对话式搜索中的广告检测——Detecting Generated Native Ads in Conversational Search

Detecting Generated Native Ads in Conversational Search | Companion Proceedings of the ACM on Web Conference 2024https://dl.acm.org/doi/abs/10.1145/3589335.3651489 1. 概述 大型语言模型(LLMs)已成为构建对话式搜索引擎与检索增强生成系统的主流标准。然而,在大…

python packages是什么意思

package指的就是包&#xff0c;它是一个有层次的文件目录结构&#xff0c;它定义了由n个模块或n个子包组成的python应用程序执行环境。通俗一点&#xff1a;包是一个包含__init__.py 文件的目录&#xff0c;该目录下一定得有这个__init__.py文件和其它模块或子包。 但是这会分…

【传知代码】疯狂交互学习的BM3推荐算法(论文复现)

在当今信息爆炸的时代&#xff0c;我们每天接触的数据量已经超出我们大脑的处理能力。在这个背景下&#xff0c;个性化推荐系统以其独特的能力和智能化的算法引起了广泛关注。其中&#xff0c;基于行为的推荐系统成为了引领潮流的前沿技术之一&#xff0c;本文将深入探讨疯狂交…

未来已来:AI在提升企业客户服务质量与效率中的应用

随着人工智能&#xff08;AI&#xff09;技术的飞速发展&#xff0c;其在企业客户服务领域的应用正以前所未有的速度改变着我们的服务模式。AI技术的引入&#xff0c;不仅极大地提升了客户服务的效率&#xff0c;还显著提高了客户满意度&#xff0c;为企业创造了新的竞争优势。…

【kubernetes】kubeadm部署k8s集群

1、环境准备 master01: 192.168.10.25master02: 192.168.10.26master03: 192.168.10.27node01: 192.168.10.28node02: 192.168.10.29负载均衡器1&#xff1a;192.168.10.30负载均衡器2&#xff1a;192.168.10.31 //所有节点&#xff0c;关闭防火墙规则&#xff0c;关闭selinu…

秋招突击——算法训练——8/1——用友集团笔试

文章目录 引言正文小友的生产线个人实现参考实现 小友策划游戏人物个人实现参考实现 最佳工作任务安排个人实现参考实现 大众评分最高的一次旅程 总结 引言 今天晚上七点钟到九点钟是用友集团的笔试&#xff0c;作为今天算法练习的主要内容&#xff01;具体怎么样&#xff0c;…

MinIO DataPod:百亿亿次级计算的参考架构

现代企业通过其数据来定义自己。这需要用于 AI/ML 的数据基础设施&#xff0c;以及作为现代数据湖基础的数据基础设施&#xff0c;该数据基础设施能够支持商业智能、数据分析和数据科学。如果他们落后、起步或使用 AI 获得高级见解&#xff0c;则情况确实如此。在可预见的未来&…

又一个GPT4级的模型免费了?MiniMax史诗级更新

又有一个超性价比的国产大模型出现了&#xff01;这里是智匠AI&#xff0c;MiniMax刚刚对他们的主力模型abab6.5s&#xff0c;进行了大幅降价&#xff0c;输入和输出成本都达到了1元/百万tokens。我们今天就来进行评测这款abab6.5s。 abab6.5s在文科任务、内容理解、文字生成及…

WebKit引擎:探索现代网页渲染的幕后魔法!

WebKit 是一个开源的浏览器引擎&#xff0c;它负责解析和渲染网页内容&#xff0c;包括HTML、CSS和JavaScript。WebKit的工作流程涵盖了加载资源、解析文档、应用样式、布局渲染树等一系列步骤&#xff0c;最终将网页内容呈现在用户的屏幕上。 WebKit简介 WebKit是一个开源的浏…

Python在气象与海洋中的应用

Python是功能强大、免费、开源&#xff0c;实现面向对象的编程语言&#xff0c;能够在不同操作系统和平台使用&#xff0c;简洁的语法和解释性语言使其成为理想的脚本语言。除了标准库&#xff0c;还有丰富的第三方库&#xff0c;并且能够把用其他语言&#xff08;C/C、Fortran…