【TCP】确认应答、超时重传机制和TCP报头

简介: 【TCP】确认应答、超时重传机制和TCP报头

TCP 相关机制

TCP 基本特点:有连接、可靠传输、面向字节流、全双工

  • 有连接、面向字节流和全双工都能在前面的代码中体现
  • 有连接:必须要先调用 accept 建立联系才能处理
  • 面向字节流:会拿到 clientSocket 对象的 InputStreamOutputStream,再来去读写数据
  • 全双工:一个 Socket 对象,既可以读,也可以写
    而此处的可靠传输在代码层面感知不到,它是在系统内核完成了这里的工作

TCP 最核心的资质就是“可靠传输”,不能做到 100% 送达,只能尽可能的是数据能到达对方方

  1. 能感知到对方是否收到
  2. 如果发现对方没有收到,就要进行重试

后发先至

  • 如果数据按照左边的传输次序来的,那就不会有歧义
  • 虽然女神先发的“好啊好啊”,后发的“滚”,但是在网络传输中,可能存在“后发先至”,对于我们接收方来说,可能会先收到“滚”,后收到“好啊好啊”
  • 此时,歧义就产生了,我将会误以为女神答应我了

出现原因

互联网最初是用来防御核弹打击的,即使是遭受到了核弹打击,但是 A~B 之间的通信路径有很多很多条,不会全军覆没,所以仍然可以确保数据能正常传输

  • 在正常传输数据的时候,传输数据包不一定走同一条路线
  • 因为是不同的路线,每个数据包传输过程中,遇到的状况也都有差别,最终达到目标的时序就可能存在差异了

举个例子:一个婚车队伍,在触发的时候都是按照顺序,一辆一辆跟着走的,但一到大路上,车队就可能会走散

  • 本来跟着头车走,结果遇到了红灯,一旦跟不上,就各凭本事了
  • 每辆车,各个导航,可能走的路线都不一样,可能有的车还会堵车
  • 最后到达目的地的先后顺序改变的情况就是很常见的

1. 确认应答

后发先至的解决方法,TCP 核心机制,感知对方是否收到,就是要靠对方告诉你一声“收到了”

  • 后发先至是客观存在的情况,无法改变
    若要解决,可以给传输的数据添加“编号”,通过编号,可以区分出数据的先后顺序
  • 我收到的应答报文,即使顺序出现错乱,也能识别出来原意
  • 由于 TCP 是面向字节流的,是加上这里的编号并非是按照“第一条,第二条”这样的方式来编排的,而是按照“字节“,“第一个字节,第一百个字节”,这样来编排的
  • 每个字节都有一个独立的编号,字节和字节之间,编号是连续的、递增的
  • 这种按照字节编号的机制,就成为“TCP 的序号”,在应答报文中,针对之前收到的数据进行对应的编号,称为“TCP 的确认序号

之后,TCP 就可以针对接收方收到的信息,进行重新排序,确保应用程序 read 到的数据一定是和发送方的数据顺序是一致的

接收方这边调用 read 的时候如果没有数据,就会阻塞等待(前面回显服务器文章中写的是 scanner 读取,本质上就是调用 InputStream.read

  • 接收方收到的数据信息顺序可能和发送发传输时的顺序不一样
  • 此时接收方收到 1001-2000 这个数据到了,但是接收方不会让 read 接触阻塞,因为这个数据的起始部分还没到,2001-3000 到了之后也进行阻塞
  • 直到1-1000这个数据到达之后,read才会接触阻塞,才会读取到1-10001001-20002001-3000
  • 接收方这边,操作系统内核里面,有一段空间,作为“接收缓冲区”,收到的数据就会先在缓冲区中排队等待,直到开头的数据到了,应用程序才能真正读取到里面的数据

前面接亲的例子:等婚车到了女方门口,因为头车还没来,所以不能直接开到新娘门口去接人

  • 因此这样的车就得在外等待,必须等头车到
  • 等车到了之后,再重新排好队,再一起开到新娘家门口

丢包

丢包的原因有很多种:

  1. 数据传输的过程中,发生了 bit 翻转,收到这个数据的接收方/中间的路由器什么的,计算校验和,但是发现校验和对不上
    发现错误,要及时止损,不能将错就错
  • 所以就会把这个数据丢弃掉,不继续往后转发/不交给应用层使用

  1. 数据传输到某个节点(路由器/交换机),但这个节点的负载太高了,后续传输过来的数据就可能被这个路由器直接丢弃
  • 负载太高:某个路由器,单位时间只能转发 N 个包,但现在是网络高峰期,这个路由器单位时间需要转发的包超过 N 个了,发不过来了

2. 超时重传

发生丢包是完全随机,不可预测的,TCP 再怎么厉害,也不可能避免数据发生丢包。TCP 能做的是:感知到数据是否丢失,如果丢包,就重新再发一次

此时需要通过应答报文来区分

  • 收到应答报文,说明数据没丢包
  • 没收到应答报文,就说明数据丢包了
  • 网络传输是需要消耗时间的,这里的“没收到”是暂时没收到,还是永远都收不到?
  • 发送方发送数据之后,会给出一个“超时时间”,如果在这个时间限制之内,没有收到反馈的 ACK(应答报文 ACK 由 0 变为 1),就视为数据丢包了

    不管是因为数据丢了导致的丢包还是因为 ACK 丢了导致的,都会重发
  • 但如果是因为 ACK 丢了导致的重发,接收方就会收到两份一样的数据,这样是很不好的(一次扣款请求扣两次)
  • 所以为了确保应用程序调用read读出来的数据是唯一、不重复的,TCP 就会对这种情况进行处理——去重
  • 接收方有一个“接收缓冲区”,收到的数据会先进入到缓冲区里,后续再督导数据,就会根据序号,在缓冲区中找到对应的位置(排序)。如果发现当前序号 1-1000 这个数据已经在缓冲区中存在了,就会直接把新收到的这个数据丢弃掉

超时时间的设定

这里的时间不是固定不动的,而是动态变化的

发送方第一次重传,超时时间是 t1,如果重传之后,仍然没有 ACK,就会继续重传,第二次重传的超时时间是 t2t2>t1

  • 每多重传一次,超时时间的间隔就会变大,重传的频次会降低
  • 经过一次重传之后,就能让数据到达的概率提升很多
  • 反之,如果重传了几次,都没有顺利到达,说明网络的丢包率已经达到了一个非常高的程度——>网络发生了严重故障,大概率没法继续使用了
    重传也不会无休止的进行,当重传达到一定次数之后,TCP 不会再重传,就认为这个连接已经挂了
  • 先尝试进行“重置/复位连接”,发送一个特殊的数据包“复位报文”,尝试和对方重新进行连接
  • 如果网络这会恢复了,复位报文就会重置连接,使通信可以继续进行
  • 如果网络还有严重问题,复位报文也没有得到回应,此时 TCP 就会单方面放弃连接(发送方释放掉之前接收方的相关信息,这个连接诶也就没了)

确认应答和超时重传相互补充,共同构建了 TCP 的“可靠传输机制

  • 可靠传输机制不是靠“三次握手和四次挥手保证的”

TCP 报头

首部长度

TCP 报头的长度

  • UDP 协议报头固定就是 8 个字节
  • 对于 TCP 来说,报头长度是可变的
    4 个比特位可表示的范围:
  • 0000~1111——>0x0~0xF——>0~15
  • 此处的长度单位是 4 字节,不是字节(所以范围是 0~60 字节)

保留(6 位)

虽然现在不用,但是先把这个东西申请下来,以备不时之需。用于考虑未来的可扩展性

  • 充分吸取了 UDP 的教训,UDP 的报文长度字段,是没法扩展的
  • 如果未来某一天,TCP 需要新增属性或者谋和属性的长度不够用,就可以把保留位拿出来,进行使用
  • TCP 的结构不需要发生太大的改变,这样的升级就会容易很多

关于“可扩展性”也是属于编程的时候需要考虑到的一点,毕竟写的代码不可能写一份就能持续地使用。对代码做出调整,做出修改,是非常普遍、常见的情况

但是,

选项

TCP 报头边长的主要原因。四个字节为一个单位

  • 可以有, 也可以没有
  • 可有一个,也可有多个
    通过“首部长度”确定报头有多长,如果是两个四个字节长度就是两个选项,三个四个字节长度就是三个选项,以此类推

序号

由于会出现“后发先至”的情况,所以需要通过编号,区分出数据的先后顺序

序号:表示的就是 TCP 数据报载荷中的第一个字节的序号,由于序号是连续递增,知道了第一个字节的序号,后续每个字节的序号也就知道了

  • 32 位/四字节,表示的范围是 0~42亿9千万0~4G
  • 因为 TCP 是面向字节流的,所以一个 TCP 数据报和下一个 TCP 数据报携带的数据,是可以直接进行拼装的
  • 比如要传输一个特别大的数据,传输过程中,本身就会通过多个TCP数据报来进行携带,这些TCP数据报彼此之间携带的载荷都是可以在接受方自动拼起来的
  • 这样就不像 UDP 存在传输的上限,使用 UDP 传输大数据,就需要考虑调用这一次 send 操作,参数是否超过了 64KB,超过了就不行
  • 使用 TCP 的话就没关系,可以调用一次 write,也可以调用多次 write。无论怎么进行 write,在网络传输和对端接收的角度来看是没有任何差别的
  • 如果多次 write,传输的总数据量超过上述的 4G 也没关系,这里的数据序号是可以再从 0 开始重新设置的

确认序号

确认序号的设定方式,和后发先至中发短信的例子,略有差别

  • TCP 序号不是按照“一条两条”来编排的,而是按照“字节”来编排的

TCP 的确认序号这里,填写的是 1001,接收方收到的数据的最后一个字节序号的下一个序号

  • 表示的含义是 <1001 的序号的数据都收到了(TCP 序号是连续增长的)
  • 对于应答报文来说,“确认序号”就会按照收到的数据的最后一个字节序号+1 的方式来填写
  • 并且六个标志位中,第二个标志位(ACK)会设为1
  • 普通报文的 ACK0,应答报文的 ACK1
  • 如果是普通报文,序号是有效的,确认序号是无效的;如果是应答报文,序号和确认序号都是有效的
  • 应答报文的序号是另一套编号体系,和传输数据的序号是不一样的
  • 应答报文默认情况下是不携带数据的


相关文章
|
24天前
|
弹性计算 人工智能 架构师
阿里云携手Altair共拓云上工业仿真新机遇
2024年9月12日,「2024 Altair 技术大会杭州站」成功召开,阿里云弹性计算产品运营与生态负责人何川,与Altair中国技术总监赵阳在会上联合发布了最新的“云上CAE一体机”。
阿里云携手Altair共拓云上工业仿真新机遇
|
16天前
|
存储 关系型数据库 分布式数据库
GraphRAG:基于PolarDB+通义千问+LangChain的知识图谱+大模型最佳实践
本文介绍了如何使用PolarDB、通义千问和LangChain搭建GraphRAG系统,结合知识图谱和向量检索提升问答质量。通过实例展示了单独使用向量检索和图检索的局限性,并通过图+向量联合搜索增强了问答准确性。PolarDB支持AGE图引擎和pgvector插件,实现图数据和向量数据的统一存储与检索,提升了RAG系统的性能和效果。
|
20天前
|
机器学习/深度学习 算法 大数据
【BetterBench博士】2024 “华为杯”第二十一届中国研究生数学建模竞赛 选题分析
2024“华为杯”数学建模竞赛,对ABCDEF每个题进行详细的分析,涵盖风电场功率优化、WLAN网络吞吐量、磁性元件损耗建模、地理环境问题、高速公路应急车道启用和X射线脉冲星建模等多领域问题,解析了问题类型、专业和技能的需要。
2577 22
【BetterBench博士】2024 “华为杯”第二十一届中国研究生数学建模竞赛 选题分析
|
18天前
|
人工智能 IDE 程序员
期盼已久!通义灵码 AI 程序员开启邀测,全流程开发仅用几分钟
在云栖大会上,阿里云云原生应用平台负责人丁宇宣布,「通义灵码」完成全面升级,并正式发布 AI 程序员。
|
3天前
|
JSON 自然语言处理 数据管理
阿里云百炼产品月刊【2024年9月】
阿里云百炼产品月刊【2024年9月】,涵盖本月产品和功能发布、活动,应用实践等内容,帮助您快速了解阿里云百炼产品的最新动态。
阿里云百炼产品月刊【2024年9月】
|
2天前
|
存储 人工智能 搜索推荐
数据治理,是时候打破刻板印象了
瓴羊智能数据建设与治理产品Datapin全面升级,可演进扩展的数据架构体系为企业数据治理预留发展空间,推出敏捷版用以解决企业数据量不大但需构建数据的场景问题,基于大模型打造的DataAgent更是为企业用好数据资产提供了便利。
163 2
|
20天前
|
机器学习/深度学习 算法 数据可视化
【BetterBench博士】2024年中国研究生数学建模竞赛 C题:数据驱动下磁性元件的磁芯损耗建模 问题分析、数学模型、python 代码
2024年中国研究生数学建模竞赛C题聚焦磁性元件磁芯损耗建模。题目背景介绍了电能变换技术的发展与应用,强调磁性元件在功率变换器中的重要性。磁芯损耗受多种因素影响,现有模型难以精确预测。题目要求通过数据分析建立高精度磁芯损耗模型。具体任务包括励磁波形分类、修正斯坦麦茨方程、分析影响因素、构建预测模型及优化设计条件。涉及数据预处理、特征提取、机器学习及优化算法等技术。适合电气、材料、计算机等多个专业学生参与。
1576 16
【BetterBench博士】2024年中国研究生数学建模竞赛 C题:数据驱动下磁性元件的磁芯损耗建模 问题分析、数学模型、python 代码
|
22天前
|
编解码 JSON 自然语言处理
通义千问重磅开源Qwen2.5,性能超越Llama
击败Meta,阿里Qwen2.5再登全球开源大模型王座
977 14
|
4天前
|
Linux 虚拟化 开发者
一键将CentOs的yum源更换为国内阿里yum源
一键将CentOs的yum源更换为国内阿里yum源
221 2
|
17天前
|
人工智能 开发框架 Java
重磅发布!AI 驱动的 Java 开发框架:Spring AI Alibaba
随着生成式 AI 的快速发展,基于 AI 开发框架构建 AI 应用的诉求迅速增长,涌现出了包括 LangChain、LlamaIndex 等开发框架,但大部分框架只提供了 Python 语言的实现。但这些开发框架对于国内习惯了 Spring 开发范式的 Java 开发者而言,并非十分友好和丝滑。因此,我们基于 Spring AI 发布并快速演进 Spring AI Alibaba,通过提供一种方便的 API 抽象,帮助 Java 开发者简化 AI 应用的开发。同时,提供了完整的开源配套,包括可观测、网关、消息队列、配置中心等。
734 9