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位紧急指针:标识哪部分数据是紧急数据;

接下来我们来谈谈TCP常见的几个特性

1.确认应答-------用来确保可靠性最核心的机制

TCP将每个字节的数据都进⾏了编号.即为序列号.
 

每⼀个ACK都带有对应的确认序列号,意思是告诉发送者,我已经收到了哪些数据;下⼀次你从哪⾥开始发.

2.超时重传 --------确认应答的补充

没收到ack 一种情况就是丢包

如果一切顺利,通过应答报文就可以告诉发送方,当前数据是不是成功收到

这个情况下,就要超时重传了

发送方发了个数据,要等;  等的时间里收到了ack(数据报在网络上传输,需要时间)

等了好久,ack还没等到,此时发送方就认为数据的传输出现丢包

当认为丢包之后,就会把刚才的数据包在传输一次(重传)

等待的过程有一个时间阈值(上线),就是(超时)

没收到ack 另一种情况就是ack丢了

因此接收方会收到很多重复数据.那么TCP协议需要能够识别出那些包是重复的包,并且把重复的丢弃掉

接收方如何判定这个数据是否是"重复数据"   核心判定依据,数据的序号 ---序列号

a.数据还在接收缓冲区里没有被read走

此时,就拿着新收到的数据的序号,和缓冲区中的所有数据的序号对一下,看看有没有一样的

有一样的就是重复了,就可以把新收到的数据丢弃了

b.数据在接收缓冲区中,已经被应用程序read走了,此时新来的数据序号直接无法在接收缓冲区查到

超时是会重传,重传也不是无限的重传.......重传过程也是有一定的策略~~

1.重传次数是有上限的,重传到一定程度,还没有ack ,就尝试重置连接,如果重置也失败,就直接放弃连接

2.重传的超时时间阈值也不是固定不变的,随着重传次数的增加,而增大(重传频率越来越低)

        经历重传之后还是丢包,大概率是网络问题,再怎么重传也白费力气,重传还是要重传,但是可以少传几次

数据丢了,还是ack丢了,发送方角度看起来,就是区分不了,都是ack没收到

3.连接管理

1)建立连接(三次握手)

SYN称为同步报文, 意思就是向另外一放申请连接, ACK为应答报文, 意思为同意建立连接)

三次握手本质是就是检测客户端和服务器各自的发送能力和接收能力是否正常.

建⽴连接的意义:

1. 投⽯问路,确认当前通信路径是否畅通.
2. 协商参数,通信双⽅共同确认⼀些通信中的必备参数数值.

        其中一个信息挺关键的,TCP通信的序号,初始值

        TCP一次通信过程中,序号不是从0或者1开始计算的 

        而是选择一个比较大的数字,以这个数字开头来继续计算

        即使同一个客户端和服务器,每次连接没开始的序号都不同 

2)断开连接(四次挥手)

断开连接的本质:把对方信息从数据结构中给删除掉

       

四次挥手能否像三次握手一样,把中间两次交互合并?

有时候能合并,有时候不能合并,不像三次握手一样,100%合并

在实际通信过程中,ack 和第二个fin时间间隔比较长,此时就无法进行合并,就分两次进行传输

四次挥手和三次握手有什么区别?

相似

都是通信双方各自给对方发起一个syn/fin,各自给对方返回ack

数据传输的顺序,syn/ack/syn/ack       fin/ack/fin/ack

不同

三次握手中间两次一定能合并,四次挥手则不一定

三次握手,必须是客户端主动,    四次挥手 ,客户端/服务器都可以主动

确认应答,超时重传,连接管理----->可靠传输,可靠传输也付出了代价 传输效率

4.滑动窗口  ----->TCP中非常有特点的机制

确认应答机制下,每次发送方收到一个ack才会发下一个数据,导致大量的时间都消耗在等待ack上了

滑动窗口提出就是为了解决上述问题的,滑动窗口就可以在保证可靠传输的基础上,提高效率(这里的提高效率其实是降低损失,而不是增加速度)

• 窗⼝⼤⼩指的是⽆需等待确认应答⽽可以继续发送数据的最⼤值.上图的窗⼝⼤⼩就是4000个字节(四个段).
• 发送前四个段的时候,不需要等待任何ACK,直接发送;
• 收到第⼀个ACK后,滑动窗⼝向后移动,继续发送第五个段的数据;依次类推;
• 操作系统内核为了维护这个滑动窗⼝,需要开辟发送缓冲区来记录当前还有哪些数据没有应答;只
有确认应答过的数据,才能从缓冲区删掉;
• 窗⼝越⼤,则⽹络的吞吐率就越⾼;

那么如果出现了丢包,如何进⾏重传?这⾥分两种情况讨论.
情况⼀:数据包已经抵达,ACK被丢了


这种情况下,部分ACK丢了并不要紧,因为可以通过后续的ACK进⾏确认;

情况⼆:数据包就直接丢了.


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

确认应答 超时重传  滑动窗口  快速重传   并不冲突 ,而且是同时存在

滑动窗口中当然也有确认应答,只不过把等待的策略稍作调整,转成批量的

批量的前提,短时间发了很多数据,如果发的数据很少,此时滑动窗口滑不起来,退化成确认应答

如果当前传输过程是按照滑动窗口(短时间传输大量数据) 就按照快速重传保证可靠性.此时判定丢包的标准就是看连续多少个ack索要数据

如果当前传输过程不是按照滑动窗口(没有传很多数据),此时仍按照之前的超时重传保证可靠性,此时判断丢包就是达到超时时间还没有ack到达

5.流量控制(流控)

通过滑动窗口可以提高传输效率

窗口大小越大,更多的数据复用同一块时间等待,效率就越高(批量传多少数据不需要等待ack,此时数据的量就称为"窗口大小")

接收端处理数据的速度是有限的.如果发送端发的太快,导致接收端的缓冲区被打满,这个时候如果发送端继续发送,就会造成丢包,继⽽引起丢包重传等等⼀系列连锁反应.
因此TCP⽀持根据接收端的处理能⼒,来决定发送端的发送速度.这个机制就叫做流量控制(Flow
Control);

• 接收端将⾃⼰可以接收的缓冲区⼤⼩放⼊TCP⾸部中的"窗⼝⼤⼩"字段,通过ACK端通知发送端;
• 窗⼝⼤⼩字段越⼤,说明⽹络的吞吐量越⾼;
• 接收端⼀旦发现⾃⼰的缓冲区快满了,就会将窗⼝⼤⼩设置成⼀个更⼩的值通知给发送端;
• 发送端接受到这个窗⼝之后,就会减慢⾃⼰的发送速度;
• 如果接收端缓冲区满了,就会将窗⼝置为0;这时发送⽅不再发送数据,但是需要定期发送⼀个窗⼝探测数据段,使接收端把窗⼝⼤⼩告诉发送端.

接收端如何把窗⼝⼤⼩告诉发送端呢?回忆我们的TCP⾸部中,有⼀个16位窗⼝字段,就是存放了窗⼝⼤⼩信息;
那么问题来了,16位数字最⼤表⽰65535,那么TCP窗⼝最⼤就是65535字节么?
实际上,TCP⾸部40字节选项中还包含了⼀个窗⼝扩⼤因⼦M,实际窗⼝⼤⼩是窗⼝字段的值左移M位;

6.拥塞控制   限制发送方发送数据的速率

                     流量控制是站在接收方的角度来制约发送方速率的

总的原则是,流量控制和拥塞控制,谁产生的窗口大小更小,谁就说了算

这个拥塞控制具体是怎么这个窗口大小给试出来de?

1.慢启动,刚开始传输得数据,速率是比较小的,采用的窗口大小也就比较小

   此时,网络的拥堵情况未知,如果一上来就搞很大,可能就让本来不富裕的网络带宽,就雪上加霜了

2.如果上述传输的数据,没有出现丢包,,说明网络还是畅通的,就增加窗口大小,此时,增大方式是按指数来增长的

 由于使用慢启动,开始的时候,窗口大小非常小,也有可能网络上就是很畅通,通过指数增长可以让上述的窗口大小快速变大,这样就可以保证传输的效率

3.指数增长,不会一直持续保持的,可能会增长太快,一下就导致网络拥堵

    这里引入一个阈值,当拥塞窗口达到阈值之后,此时,指数增长就成了线性增长

    线性增长能使当下的窗口持久保持在一个比较高的速率,并且也不容易一下就造成丢包

4.线性增长也是一直在增长,积累一段时间之后,传输的速率可能过快,此时还是会引起丢包

   一旦出现丢包.就把拥塞窗口重置成一个较小的值,回到最初的 慢启动 过程(又要重新指数增长)

   并且这里也会根据刚才丢包时窗口大小,重新设置指数增长到线性增长的阈值

7. 延时应答

也是基于滑动窗口,是要尽可能的再提高一点效率

结合滑动窗口以及流量控制,能够通过延时应答ack的方式.把反馈的窗口大小,搞大一些

接收收到数据之后,不会立即返回ack,而是稍等一下,等一会再返回ack.等了这一会,相当于给接收方的应用程序这里,腾出来更多的时间,来消费这里的数据

核心就在于允许的范围内,让窗口尽可能的大

那么所有的包都可以延迟应答么?肯定也不是;

• 数量限制:每隔N个包就应答⼀次;
• 时间限制:超过最⼤延迟时间就应答⼀次;
具体的数量和超时时间,依操作系统不同也有差异;⼀般N取2,超时时间取200ms;


8.捎带应答   基于延时应答,引入的机制,能够提高传输效率

修改窗口大小,确实是提升效率的有效途径

捎带应答,就是走另一条路,尽可能的把能合并的数据包进行合并,从而起到提高效率的效果

9.⾯向字节流

创建⼀个TCP的socket,同时在内核中创建⼀个发送缓冲区和⼀个接收缓冲区;

• 调⽤write时,数据会先写⼊发送缓冲区中;
• 如果发送的字节数太⻓,会被拆分成多个TCP的数据包发出;
• 如果发送的字节数太短,就会先在缓冲区⾥等待,等到缓冲区⻓度差不多了,或者其他合适的时机发送出去;
• 接收数据的时候,数据也是从⽹卡驱动程序到达内核的接收缓冲区;
• 然后应⽤程序可以调⽤read从接收缓冲区拿数据;
• 另⼀⽅⾯,TCP的⼀个连接,既有发送缓冲区,也有接收缓冲区,那么对于这⼀个连接,既可以读数据,也可以写数据.这个概念叫做全双⼯

由于缓冲区的存在,TCP程序的读和写不需要⼀⼀匹配,例如:

• 写100个字节数据时,可以调⽤⼀次write写100个字节,也可以调⽤100次write,每次写⼀个字节;
• 读100个字节数据时,也完全不需要考虑写的时候是怎么写的,既可以⼀次read100个字节,也可以⼀次read⼀个字节,重复100次;

粘包问题

• ⾸先要明确,粘包问题中的"包",是指的应⽤层的数据包
• 在TCP的协议头中,没有如同UDP⼀样的"报⽂⻓度"这样的字段,但是有⼀个序号这样的字段.
• 站在传输层的⻆度,TCP是⼀个⼀个报⽂过来的.按照序号排好序放在缓冲区中.
• 站在应⽤层的⻆度,看到的只是⼀串连续的字节数据
• 那么应⽤程序看到了这么⼀连串的字节数据,就不知道从哪个部分开始到哪个部分,是⼀个完整的应⽤层数据包.

那么如何避免粘包问题呢?归根结底就是⼀句话,明确两个包之间的边界.

• 对于定⻓的包,保证每次都按固定⼤⼩读取即可;例如上⾯的Request结构,是固定⼤⼩的,那么就从缓冲区从头开始按sizeof(Request)依次读取即可;
• 对于变⻓的包,可以在包头的位置,约定⼀个包总⻓度的字段,从⽽就知道了包的结束位置;
• 对于变⻓的包,还可以在包和包之间使⽤明确的分隔符(应⽤层协议,是程序猿⾃⼰来定的,只要保证分隔符不和正⽂冲突即可);

思考:对于UDP协议来说,是否也存在"粘包问题"呢?

• 对于UDP,如果还没有上层交付数据,UDP的报⽂⻓度仍然在.同时,UDP是⼀个⼀个把数据交付给应⽤层.就有很明确的数据边界.
• 站在应⽤层的站在应⽤层的⻆度,使⽤UDP的时候,要么收到完整的UDP报⽂,要么不收.不会出现"半个"的情况.

10.异常情况

1)其中有一方出现了 ,进程崩溃

进程无论是正常结束还是异常崩溃,都会触发到回收文件资源,关闭文件这样的效果(系统自动完成)就会触发 四次挥手

TCP连接的生命周期,可以比进程更长一些,虽然进程已经退出了,但是TCP连接还在,仍然可以继续四次挥手

虽然说是异常崩溃,实际上和正常的四次挥手结束,没啥区别,进程不在了,是通过系统中仍然持有的连接信息,完成后续的挥手过程的

3)其中一方出现断电(直接拔电源,也是关机,更突然性的关机)

如果直接断电,机器瞬间关机,此时,肯定来不及发送fin

a.断电是接收方,发送方就会突然发现,没有ack了,就要重传,重传几次之后还是,还是不行

TCP就会尝试"复位"连接(相当于清除原来的TCP中的各种临时数据,重新开始)

需要用到一个TCP中的"复位报文段"

b.断电是发送方?接收方本来就是在阻塞等待发送方的消息,迟迟没来消息,咋办

这种情况下,接收方需要区分出,发送方是挂了,还是好着暂时没法

TCP中也是如此,接收方一段时间之后,没有收到对方的消息,就会触发"心跳包"来询问对方的情况

如果对端没心跳了,此时本端也就会尝试复位并且单方面释放连接了

心跳包:也是不携带应用层数据的特殊数据包

1.周期性

2.没有心跳,视为是对端挂了

4)网线断开

⼩结


为什么TCP这么复杂?因为要保证可靠性,同时⼜尽可能的提⾼性能.
可靠性:
• 校验和
• 序列号(按序到达)
• 确认应答
• 超时重发
• 连接管理
• 流量控制
• 拥塞控制
提⾼性能:
• 滑动窗口
• 快速重传
• 延迟应答
• 捎带应答
其他:
• 定时器(超时重传定时器,保活定时器,TIME_WAIT定时器等)

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

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

相关文章

如何使用ROS和easymqos快速搭建一辆语音控制导航的机器人

之前做的机器人小车基本都属于电脑或手机控制操作。目前,使用语音控制机器人小车运动,让机器人导航去指定地点,已经成为热门,并且语音识别技术已经有落地方案,可满足生活中的基本需要。有些语音芯片通过高算力处理器运…

【HBase入门与实战】一文搞懂HBase!

HBase入门与实战 目录 HBase入门与实战内容要点一、引入HBase二、了解NoSQL的概念三、NoSQL、BI、大数据的关系四、HBase概述五、HBase应用场景 内容要点 HBase的引入、定义和特点NoSQL数据库的概念和与关系型数据库的区别HBase的物理架构和逻辑架构HBase Shell的基本命令使用…

PHP异世界云商系统开源源码

系统更新与修复列表 1. 基于彩虹的二次开发 - 对彩虹系统进行了二次开发,增强了系统的功能和性能。2. 新增自定义输入框提示内容(支持批量修改) - 用户可以自定义输入框的提示内容,并支持批量修改,提升用户体验。3. 新…

劲仔食品三年倍增,抢先打响鹌鹑蛋“健康”属性品牌之争?

如果说,进入2024年后,在股价继续陷入回调状态的食品板块中有个股走势表现相对亮眼,那么劲仔食品必是其中之一。 从去年发布2023年三季度业绩公告以来,其强劲的业绩表现就带动了股价走出小趋势。2023年10月23日至今2024年3月13日收…

C#构建类库

类库程序集能将类型组合成易于部署的单元(DLL文件),为了使编写的代码能够跨多个项目重用,应该将他们放在类库程序集中。 一、创建类库 在C#中,构建类库是指创建一个包含多个类的项目,这些类可以被其他应用…

RocketMQ 面试题及答案整理,最新面试题

RocketMQ的消息存储机制是如何设计的? RocketMQ消息存储机制的设计原理: 1、CommitLog文件: 所有的消息都存储在一个连续的CommitLog文件中,保证了消息的顺序写入,提高写入性能。 2、消费队列: 为每个主…

Task-balanced distillation for object detection用于

Task-balanced distillation for object detection用于目标检测的任务平衡蒸馏 摘要 主流的目标检测器通常由分类和回归两个子任务组成,由两个并行头部实现。这种经典的设计范式不可避免的导致分类得分和定位质量(IOU)之间的空间分布不一致…

漫途桥梁结构安全监测方案,护航桥梁安全!

桥梁作为城市生命线的重要组成部分,承载着城市交通、物流输送、应急救援等重要职能。然而,随着我国社会经济的飞速发展,桥梁所承载的交通流量逐年增长,其安全性所面临的挑战亦日益严峻。例如恶劣的外部环境、沉重的荷载以及长期使…

python爬虫实战——抖音

目录 1、分析主页作品列表标签结构 2、进入作品页前 判断作品是视频作品还是图文作品 3、进入视频作品页面,获取视频 4、进入图文作品页面,获取图片 5、完整参考代码 6、获取全部作品的一种方法 本文主要使用 selenium.webdriver(Firef…

HarmonyOS NEXT应用开发—自定义视图实现Tab效果

介绍 本示例介绍使用Text、List等组件,添加点击事件onclick,动画,animationTo实现自定义Tab效果。 效果预览图 使用说明 点击页签进行切换,选中态页签字体放大加粗,颜色由灰变黑,起到强调作用,同时&…

揭示数据在内存中存储的秘密!

** ** 悟已往之不谏,知来者犹可追 ** ** 创作不易,宝子们!如果这篇文章对你们有帮助的话,别忘了给个免费的赞哟~ 整数在内存中的存储 整数的表达方式有三种:原码、反码、补码。 三种表示方法均有符号位和数值位两部分…

Oracle数据库:使用 bash脚本 + 定时任务 自动备份数据

Oracle数据库:使用 bash脚本 定时任务 自动备份数据 1、前言2、为什么需要自动化备份?3、编写备份脚本4、备份脚本授权5、添加定时任务6、重启 crond / 检查 crond 服务状态7、备份文件检查 💖The Begin💖点点关注,收…

torch.backends.cudnn.benchmark 作用

相关参数 torch.backends.cudnn.enabled torch.backends.cudnn.benchmark torch.backends.cudnn.deterministictorch.backends.cudnn.benchmark True:将会让程序在开始时花费一点额外时间,为整个网络的每个卷积层搜索最适合它的卷积实现算法&#xff0c…

力扣59. 螺旋矩阵 II

思路:此题思路就是绕圈遍历,全靠条件处理技巧,重点要清楚的就是循环不变量:左闭右开(即拐弯处的一个数,留给第二行处理) 以下是代码随想录的作者的一张图片,每次for循环,…

Docker容器化技术(使用Docker搭建论坛)

第一步:删除容器镜像文件 [rootlocalhost ~]# docker rm -f docker ps -aq b09ee6438986 e0fe8ebf3ba1第二步:使用docker拉取数据库 [rootlocalhost ~]# docker run -d --name db mysql:5.7 02a4e5bfffdc81cb6403985fe4cd6acb0c5fab0b19edf9f5b8274783…

深入浅出计算机网络 day.2 概论⑥ 计算机网络体系结构

上帝疯狂杜撰世界悲情的命题 将凉薄和荒芜尽写 —— 24.3.13 内容概述 1.常见的三种计算机网络体系结构 2.计算机网路体系结构分层的必要性 3.计算机网络体系结构分层思想举例 4.计算机网络体系结构中的专用术语 一、常见的三种计算机网络体系结构 1.OSI参考模型 …

基于ElasticSearch存储海量AIS数据:时空立方体索引篇

文章目录 引言I 时间维切分II 空间范围切分引言 索引结构制约着查询请求的类型和处理方式,索引整体架构制约着查询请求的处理效率。随着时间推移,AIS数据在空间分布上具备局部聚集性,如 果简单地将所有AIS数据插入一个索引结构,随着数据量增长,索引的更新效率、查询效率及…

【Linux】Centos7上安装MySQL5.7

目录 1.下载安装包2. 上传安装包3.将 mysql 解压到/usr/local/4.重命名5.创建mysql用户及用户组6. 进入 mysql 目录修改权限7. 安装依赖库8. 执行安装脚本9. 复制启动脚本到资源目录10. 拷贝 my.cnf,并赋予权限11. 配置环境变量12. 启动 mysqld13. 登录 MySQL&#…

vite打包时发布时,放在服务器的二级目录中

方式一 hash模式 如果我们的站点根目录为 public , 我们访问的时候使用的是 http://www.abc.com/ 访问到了站点的根目当,现在我们要访问 http://www.abc.com/mysite/#/ 配置如下 修改 vite.config.js base:“/mysite/” 修改 router中的配置 上面的步骤完成&…

安装Pytorch——CPU版本

安装Pytorch——CPU版本 1. 打开pytorch官网2. 选择pip安装pytorch-cpu3.复制安装命令4. 在cmd命令窗口,进入你的虚拟环境4.1 创建虚拟环境4.2 进行安装 5. 安装成功6. 进行测试——如下面步骤,如图6.1 输入 python6.2 输入 import torch6.2 输入 print …