TCP原理特性详解



文章目录

  • 可靠传输机制
    • 1.确认应答
    • 2.超时重传
    • 2.连接管理
      • 1.三次握手
      • 2.四次挥手
  • 传输效率
    • 1.滑动窗口
    • 2.流量控制
    • 3.拥塞控制
    • 4.延时应答
    • 5.捎带应答
  • 面向字节流
    • 粘包问题
  • TCP异常情况

可靠传输机制

可靠性:即发送方知道数据是发送成功了,还是失败了。

1.确认应答

确认应答是TCP实现可靠传输最为核心的机制。


image-20230917130839885

主机A给主机B发送消息,B收到之后返回一个应答报文(ACK),A收到应答报文后就知道第一条消息发送成功了,于是继续发第二条消息…

  • 确认应答:即应答报文,也称为ACK报文。

  • 序号:类似数据(11000)等,TCP是面向字节流的,这里的11000这类数字就是1~1000个字节,每个字节都编有序号。因为字节编有序号,所以避免了发送的数据乱序的问题, 。image-20230917132307680

    TCP字节序号是依次累加的,第一条数据字节序号11000,第二条数据就是10012000。由于这1000个字节都属于一个TCP报文,所以每个TCP数据报头只存当前数据的第一个序号,比如第二条数据的TCP报文里存1001,再根据 TCP报文长度,就知道这条数据是1001~2000。

  • 确认序号:每个确认应答都带有数字(确认应答1001),这类数字就是确认序号,而确认序号只有应答报文拥有,ACK标志位为1,表示为应答报文,ACK标志位为0,表示不是应答报文。确认序号表示成功收到哪些数据,下一条数据从哪里开始发。确认序号返回的是收到当前数据最后一个字节序号的下一个序号,列如:收到11000个字节数据,返回1001,表示1001之前的数据都收到了,于是下一条消息是从编号为1001的位置开始发,即10012000。

2.超时重传

丢包分为两种情况:一是发送数据丢了,二是返回的ACK丢了。为了解决丢包问题,TCP引入了超时重传机制,在丢包的情况下,重新发送一份相同的数据。如何判断丢包呢?TCP引入了一个时间阈值,发送方传输一个数据,在一个规定的时间内,如果未收到ACK,不管三七二十一,都表示为丢包了,进行重传。

数据丢包:主机A发送的数据丢包了,在隔了一定的时间后,未收到主机B发来的确认应答,则会再次传输1~1000的数据

image-20230917142544706

ACK丢包:可以发现主机B收到了两次1~1000这个数据,TCP会根据这种重复数据进行去重,利用TCP的接收缓冲区进行去重。这个缓冲区相当于一个阻塞队列,当主机B读到了主机A发送的数据,主机B把这个数据放入这个阻塞队列中,再根据数据的序号排序、去重,如果序号重复则丢弃后来的数据。

image-20230917142620454

超时重传可能会重传几次,当重传次数达到一定的次数时,TCP会尝试重连,如果重连失败则彻底断开连接。重传的时候,第一次重传时间和第二次时间间隔不一样,重传次数越多时间间隔越大。

2.连接管理

在正常情况下,TCP要经过三次握手建立连接,通过四次挥手断开连接,所谓连接本质上是通信双方互存储了对方的信息,管理则是描述了连接如何连接和断开。

1.三次握手

举一个比较形象的列子:A先发一条消息,B收到后并响应,同时B再发送一条消息给A,A收到后并响应。

image-20230918125239110

三次握手本质上是四次交互,我们形象的把每次通信比喻成一次握手。通信双方,各自要发送一个“建立连接”的请求并各自返回对方一个ACK应答报文。由于主机B的响应和发送新消息(好啊+确认哈…)这两次交互的时间非常近,于是就把这两次交互合并为一次,也就成了三次握手;并且这两次合并是必须的,因为每次通信都需要封装分用,两次封装分用肯定要比一次封装分用的成本高。

image-20230918125939408

问题:四次合成了三次,那么直接合成两次可以完成吗?

答:显然是不能的。当主机A发送了一条消息:明天一起吃饭?主机B响应并发送新消息:好啊,确认哈?一起吃饭,别放鸽子。此时,主机A知道了主机B同意明天一起吃饭,但是主机B并不完全确定主机A会不会放鸽子。那么明天A和B可能也就吃不成饭了,也就意味着主机A和主机B连接建立不了!

三次握手的意义:一是建立通信双方的认同,保存对方的信息,二是为了验证通信双方各自的发送和接收是否正常;三是在每次交互会夹带一些重要信息,来协商一些重要的参数。

image-20230919104650158

客户端主动给服务器发起的建立连接请求,称为“SYN”/同步报文段(synchronize),对应着TCP报文结构里的“SYN”,然后服务器进行响应返回“SYN+ACK”,说明这条交互既是同步报文段,又是确认应答报文段,最后客户端返回一个“ACK”应答报文。

  • TCP连接有11种状态,分别是:LISTEN、SYN_SENT、SYN_RECEIVED、ESTABLISHED、FIN_WAIT_1、FIN_WAIT_2、CLOSE_WAIT、CLOSING、LAST_ACK、TIME_WAIT和CLOSED。

    建立连接时的状态:

  • LISTEN:表示服务器端的某个SOCKET处于监听状态,可以接受客户端的连接;

  • SYN_SENT:表示在发送连接请求后等待匹配的连接请求;

  • SYN_RECEIVED:表示在收到和发送一个连接请求后等待对连接请求的确认;

  • ESTABLISHED:表示已经建立了连接,可以进行数据传输;上图中客户端和服务器都有这个状态。

  • CLOSED表示TCP连接已经关闭 。

2.四次挥手

挥手和握手一样都是形象的比喻。四次挥手也是通信双方各自对对方发送一个断开连接的请求,再各自发送一个响应。

问题:中间两次是否能合并?(到了+你呢?)

答:显然不行,三次握手的两次交互之所以可以合并是因为这两次交互是同一时机,这一操作是纯内核操作,是我们感受不到的,当服务器收到syn后会立即返回ack;而四次挥手则不同,这两次交互是不同时机,当主机A的应用程序执行到socket的close方法时会触发FIN结束报文段,服务器接收到FIN后,内核会立即返回ACK,FIN是人为发送的,而ACK是由系统内核控制的,当主机B的应用程序执行到socket的close方法时也会触发FIN,应用程序执行到close方法前可能要经过很多道其他的程序代码,于是和ACK的时机相隔太久,也就不能合并为一次交互。

image-20230919111434977

image-20230919112122092

断开连接时的状态:

  • CLOSE_WAIT:表示被动断开连接一方等待FIN报文;

  • TIME_WAIT:表示主动断开连接的一方收到了对方的FIN报文,但是还没有发送ACK报文;

    TIME_WAIT的意义:

  • TIME_WAIT状态站在客户端视角认为已经断开连接了,但是此时TIME_WAIT会让连接状态继续保留,因为最后一个ACK还没有发出去,如果最后一个ACK丢包,服务器会进行超时重传,重新传一个FIN,客户端再重新发一个ACK,因此TIME_WAIT状态保留连接状态一定时间,就是为了有能力进行重传,如果重传的还是丢了,时间也到了,那么就认定为最后ACK没丢,直接断开连接。

  • TIME_WAIT保留时间为2MSL;(Max Segment Life,报文最大生存时

    间)2MSL表示为互联网上,两个节点之间数据传输消耗的最大时间,这个时间通常为60s。

传输效率

1.滑动窗口

活动窗口的目的是为了在可靠性传输的基础上提高传输效率。

基础的确认应答机制:主机A发一次数据,主机B只要收到一条数据就返回一个ACK,而主机A此时在没有收到ACK的时候,需要进行等待,才能发送下一条数据,每一次发送数据都要等一次,这就造成了不少的等待时间。

image-20230920101558133

加入活动窗口后的确认应答机制主机A不再需要等待第一条数据的ACK,可以一次性发送多条数据,再使用一份等待时间来等待一组数据返回的多个ACK,这就减少了多条等待ACK的时间。

下图是主机A一次性批量发送四条数据,主机B再批量返回四个ACK,收到一条数据就返回一条ACK,依次类推,只是说主机A不需要等第一个ACK,就可以连续发4条数据。

image-20230920101730003

把不需要等待就可以发送的最大的数据量就称为:“窗口大小”;上图这个“窗口大小”为4000。

发送一个窗口大小的数据后,主机A并不是要等这一个窗口大小的ACK全部返回了,才继续发送下面的数据,而是主机B接收到一条数据就返回一条ACK,主机A收到一个ACK就发一条数据,这样就保证了等待的ACK永远都是4条(窗口大小,处理的数据永远都是4条,而不是处理一条就没事做了)。

举个例子:比如一个人有4台电脑一台电脑可以刷一门课,同时只能刷4门课,需要刷满10门课,此时“窗口大小”就是4。当我刷完一门课后,手上正在刷的课为3门,那么就有一台电脑是空闲状态,于是我就可以再找一门课继续刷,一直保持刷4门课的状态。相当于用1门课的时间刷了4门课,用最少的时间刷完10门。

每次刷完一门课,就立即开始下一门,窗口大小始终未变,但是课程变了。类似于下图,本来需要等10015000的ACK,但是收到了2001的ACK,说明2001之前的数据已经被确认,此时可以立即发送50016000的数据,等待的ACK范围就成了2001~6000,这种现象看起来就像是在滑窗口,于是就形象的比喻成滑动窗口

image-20230920104420332

  • 滑动窗口情况下,丢包了怎么解决?

    1. ACK丢了:不需要做出任何处理!因为有确认序号,当返回2001的ACK,说明2001之前的数据都到达了,2001包含了1~2000的数据序号。image-20230920105210223

    2. 数据包丢了:下图显示,当10012000的数据丢了,主机B返回的是1001的ACK,意思是索要主机A1001开头的数据,主机A连续发送多条数据后收到的依旧是1001的ACK,这时主机A就会发送10012000的数据。当主机B成功收到10012000的数据后,由于主机A之前已经发送20017000的数据,并且主机B成功收到了,于是这次返回的是7001的ACK,说明7001之前的数据都收到了(包含10012000的数据),也就意味着主机A下次发送的数据是从7001开始。假设,40015000也丢包了,此时是返回的ACK是5001,而不是7001,即使主机A已经把数据发送到了7000。总结:丢哪个包就索要哪个包的数据。

      这种重传方式称为“快速重传”,表示只重传丢失的数据。

2.流量控制

滑动窗口提高了传输效率,可是窗口也不能无限大,因为接收方处理能力有限。流量控制的意义是为了根据接收方的处理能力来控制发送方的传输效率。

那么如何衡量接收方的处理能力呢?

可以根据接收方的接收缓冲区剩余大小来判断,比如传输10个,接收缓冲区还剩下20个,说明下次可以传输20个,或者30个,接收方都能处理过来。

比如主机A给主机B发送了一条数据,B就算一下接收缓冲区剩余空间,再把这个结果通过ACK返回给A,A根据这个结果来决定下次发送的窗口大小是多少,是连续发10个还是20个。

TCP报文结构里有16位窗口大小,即默认为64kb,而TCP为了让窗口大小可以更大,在选项中引入了窗口大小的扩展因子,比如扩展因子里是2,表示64kb左移2位即256kb。

image-20230920121358460

上图显示:第一次A传输了11000的数据,B返回1001ACK,接收缓冲区剩余大小为3000,A再次发送10014000的数据,B依次返回三个ACK 当B的接收缓冲区为0了,A机会进行等待,在等待时间,A会发送一个窗口探测报文来询问B的接收缓冲区是否有空余。

3.拥塞控制

流量控制和拥塞控制共同决定发送方的窗口大小。

流量控制表示接收方的处理能力;

拥塞控制表示传输过程中的中间节点的处理能力(中间节点:路由器,运营商等)。

中间节点的测量:通过实验来测试出一个合适的值。比如先发少量的数据,探探路,摸清当前的网络拥堵状态,再决定按照多大的速度传输数据;

下图表示实验中间节点的窗口大小:第0轮。窗口大小为1,没有丢包就扩大窗口,第二次就为2…以指数增长;当增长速率达到阈值时,变成线性增长;当丢包了也就是遇到网路拥堵,窗口大小一下子变为一个很小的值,再重新按指数增长线性增长,此时的增长速率阈值为上次网路拥堵的值除2…依次类推,直到找到不是网络拥堵的瓶颈并且是一个最大的值 。拥塞窗口会根据当前网络环境一直动态的调整。

image-20230920122455931

4.延时应答

延时应答:收到数据后,不是立刻返回ACK,而是稍等再返回。

在滑动窗口上进行改进,比如主机A第一次发送数据,B的原本接收缓冲区大小为1M,B计算后立即返回的ACK窗口大小为500kb,那么下次A传输的数据就是500kb;但是如果要是稍等再返回ACK,在这个稍等的时间内主机B把这个500kb给消费掉,那么返回的窗口大小就为1M,下次A就可以发1M的数据,从而提高传输效率。

image-20230920174000401

上图显示,实际上延时应答采取的方式为在滑动窗口下,ACK不再每一条数据都返回,比如上图隔一条返回一个ACK。

5.捎带应答

在延迟应答的基础上,我们发现,很多情况下,客户端服务器在应用层也是 “一发一收” 的。意味着客户端给服务器说了 “How are you”,服务器也会给客户端回一个 “Fine, thank you”;因为TCP存在延时应答,ACK等了一会,那么这个时候ACK就可以搭顺风车,和服务器回应的 “Fine,thank you” 一起回给客户端

image-20230920175409229

由于内核返回的ACK存在延时应答,于是等待,这时候应用层发了一条数据刚好和延时应答后返回的ACK时机相同,于是这两次合并为一次。

image-20230920175439006

面向字节流

粘包问题

接收缓冲区实际上是把收到的数据都放在一起,由于TCP的字节流的,但是应用层序read读取时,可以一次read一个字节或多个字节,读到哪里才算是一个完整的应用层数据报呢?这就导致可能read读取到的是半个数据报或是多个数据报。就好比下图,假设下图都是主机B返回的数据,主机A,read读取时,一次读8个字节,读取到了:“abcdefgh”,这种情况就叫粘包问题

解决方案:在应用层约定每个数据报之间用什么分隔符区分,比如用“\n",或者约定每个数据报的长度。

image-20230920180330887

TCP异常情况

  1. 进程崩溃:进程终止会释放文件描述符,仍然会完成四次挥手。和正常关闭没有什么区别。

  2. 主机正常关机:和进程崩溃一样。

  3. 主机掉电/网线断开:

    • 接收方掉电:发送方接收不到ACK,超时重传几次,会尝试重置连接,最后彻底放弃连接。
    • 发送方掉电:接收方收取不到数据,于是会周期性的发送一个消息,确认对方是否正常工作,这种操作称为“心跳包”。通过“心跳包”来确认通信双方是否正常。
  4. 进程崩溃:进程终止会释放文件描述符,仍然会完成四次挥手。和正常关闭没有什么区别。

  5. 主机正常关机:和进程崩溃一样。

  6. 主机掉电/网线断开:

    • 接收方掉电:发送方接收不到ACK,超时重传几次,会尝试重置连接,最后彻底放弃连接。
    • 发送方掉电:接收方收取不到数据,于是会周期性的发送一个消息,确认对方是否正常工作,这种操作称为“心跳包”。通过“心跳包”来确认通信双方是否正常。

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

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

相关文章

如何精细化管理嵌入式软件项目?ACT汽车电子与软件技术周演讲回顾

2023 ACT汽车电子与软件技术周已于8月18日在中国上海落下帷幕。展会现场,龙智技术支持部负责人、Atlassian认证专家叶燕秀与龙智技术工程师邱洁玉共同为观众带来了主题为“更好、更快、更安全:嵌入式开发中的最佳实践与工具链构建”的演讲,分…

elasticsearch内存占用详细分析

内存占用 ES的JVM heap按使用场景分为可GC部分和常驻部分。 可GC部分内存会随着GC操作而被回收; 常驻部分不会被GC,通常使用LRU策略来进行淘汰; 内存占用情况如下图: common space 包括了indexing buffer和其他ES运行需要的clas…

想要精通算法和SQL的成长之路 - 恢复二叉搜索树和有序链表转换二叉搜索树

想要精通算法和SQL的成长之路 - 恢复二叉搜索树和有序链表转换二叉搜索树 前言一. 恢复二叉搜索树二. 有序链表转换二叉搜索树 前言 想要精通算法和SQL的成长之路 - 系列导航 一. 恢复二叉搜索树 原题链接 首先,一个正常地二叉搜索树在中序遍历下,遍历…

【2023研电赛】东北赛区一等奖作品:基于FPGA的小型水下无线光通信端机设计

本文为2023年第十八届中国研究生电子设计竞赛东北赛区一等奖作品分享,参加极术社区的【有奖活动】分享2023研电赛作品扩大影响力,更有丰富电子礼品等你来领!,分享2023研电赛作品扩大影响力,更有丰富电子礼品等你来领&a…

312.戳气球

将戳气球转换到添加气球&#xff0c;记忆搜索slove(i,j)&#xff1a;在开区间(i,j)全部填满气球得到的最多硬币数&#xff0c;两端val[i]、val[j] class Solution { public:vector<vector<int>> ans;vector<int> val;int slove(int left,int right){if(left&…

【java基础学习】之DOS命令

#java基础学习 1.常用的DOS命令&#xff1a; dir:列出当前目录下的文件以及文件夹 md: 创建目录 rd:删除目录cd:进入指定目录 cd.. :退回到上级目录 cd\ : 退回到根目录 del:删除文件 exit:退出dos命令行 1.dir:列出当前目录下的文件以及文件夹 2.md: 创建目录 …

假期AI新闻热点:亚运会Al技术亮点;微软GPT-4V论文精读;Perplexity推出pplx-api;DALL-E 3多渠道测评 | ShowMeAI日报

&#x1f440;日报&周刊合集 | &#x1f3a1;生产力工具与行业应用大全 | &#x1f9e1; 点赞关注评论拜托啦&#xff01; &#x1f525; 科技感拉满&#xff0c;第19届杭州亚运会中的Al技术亮点 八年筹备&#xff0c;杭州第19届亚运会开幕式于9月23日晚隆重举行&#xff0…

输入电压转化为电流性 5~20mA方案

输入电压转化为电流性 5~20mA方案 方案一方案二方案三 方案一 XTR111是一款精密的电压-电流转换器是最广泛应用之一。原因有二&#xff1a;一是线性度非常好、二是价格便宜。总结成一点&#xff0c;就是性价比高。 典型电路 最终电路 Z1二极管处输出电流表达式&#xff1a;…

【Redis】基础数据结构-quicklist

Redis List 在Redis3.2版之前&#xff0c;Redis使用压缩列表和双向链表作为List的底层实现。当元素个数比较少并且元素长度比较小时&#xff0c;Redis使用压缩列表实现&#xff0c;否则Redis使用双向链表实现。 ziplist存在问题 不能保存过多的元素&#xff0c;否则查找复杂度…

Google-CTF-2016-Stego.pcap数据包解析

Google-CTF-2016&#xff08;a-cute-stegosaurus-100&#xff09; 前言&#xff1a;别人发的题目 随便看看 记录一下解题过程&#xff01; 知识点: 在报文段中有 6Bit 的状态控制码&#xff0c; 分别如下tcp URG&#xff1a;紧急比特&#xff08;urgent&#xff09;&#x…

echarts 中如何将 legend 设置成「直线」

Thinking系列&#xff0c;旨在利用10分钟的时间传达一种可落地的编程思想。 echarts 中如何将 legend 设置成「直线」&#xff1f; 所有图例均为直线 可以通过 itemHeight 和 itemWidth 来统一控制 legend: {itemHeight: 2,itemWidth: 20,data: [Expenses, Income]}部分是直线…

【数据结构-字符串 三】【字符串转换】字符串解码

废话不多说&#xff0c;喊一句号子鼓励自己&#xff1a;程序员永不失业&#xff0c;程序员走向架构&#xff01;本篇Blog的主题是【字符串转换】&#xff0c;使用【字符串】这个基本的数据结构来实现&#xff0c;这个高频题的站点是&#xff1a;CodeTop&#xff0c;筛选条件为&…

Linux CentOS7 yum仓库

在windows下安装一个软件很轻松&#xff0c;只要双击setup或者.exe的文件&#xff0c;安装提示连续“下一步”即可&#xff0c;然而linux系统下安装一个软件似乎并不那么轻松&#xff0c;因为我们不是在图形界面下。 本文我们将讨论如何在linux下安装一个软件。 一、linux软件…

Netron【.pt转.onnx模型展示】

接着上一篇写哈&#xff0c;如何转.onnx的。 因为是转.onnx类型的&#xff0c;需要先安装onnx的包。 这是直接pip install onnx后转onnx报的错&#xff1a; 很显然是版本问题导致的&#xff0c;so: 将export.py的脚本拉到最下面的parse_opt函数&#xff0c;把“17”改为“12”…

C# .net创建一个MVC框架工程

二、C# .net创建一个MVC框架工程 1.步骤 首先打开VS &#xff0c;然后点击创建新项目 在三个选项框中输入我们需要的项目条件 最后一步创建完毕 创建会在资源解决方案生成如图&#xff1a;

vulnhub_driftingblues7靶机渗透测试

Driftingblues7靶机 文章目录 Driftingblues7靶机信息收集web渗透获取权限另外思路靶机总结 信息收集 使用nmap扫描得到靶机ip为192.168.78.174&#xff0c;开放发端口有很多&#xff0c;而且开放了443端口&#xff0c;所以访问网站是需要https协议的 再对该网站进行目录扫描&…

如何查看端口占用(windows,linux,mac)

如何查看端口占用&#xff0c;各平台 一、背景 如何查看端口占用&#xff1f;网上很多&#xff0c;但大多直接丢出命令&#xff0c;没有任何解释关于如何查看命令的输出 所谓 “查端口占用”&#xff0c;即查看某个端口是否被某个程序占用&#xff0c;如果有&#xff0c;被哪…

【List-Watch】

List-Watch 一、定义二、工作机制三、调度过程 一、定义 Kubernetes 是通过 List-Watch 的机制进行每个组件的协作&#xff0c;保持数据同步的&#xff0c;每个组件之间的设计实现了解耦。 用户是通过 kubectl 根据配置文件&#xff0c;向 APIServer 发送命令&#xff0c;在 …

2023/10/7 -- ARM

【程序状态寄存器读写指令】 1.指令码以及格式 mrs:读取CPSR寄存器的值 mrs 目标寄存器 CPSR&#xff1a;读取CPSR的数值保存到目标寄存器中msr:修改CPSR寄存器的数值msr CPSR,第一操作数:将第一操作数的数值保存到CPSR寄存器中//修改CPSR寄存器&#xff0c;也就表示程序的状…

数据结构之堆,栈的实现

首先我们分析由于只需要尾进尾出&#xff0c;用数组模拟更简单。 实现的功能如上图。 top可以表示栈中元素个数。 capacity表示栈的容量。 首先是堆的初始化 再就是栈的插入和删除 然后实现显示栈顶元素 大小和检测是否为空的实现 销毁栈的实现&#xff08;防止内存泄露&…