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

本文涉及的产品
容器服务 Serverless 版 ACK Serverless,317元额度 多规格
容器服务 Serverless 版 ACK Serverless,952元额度 多规格
简介: 【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
  • 如果是普通报文,序号是有效的,确认序号是无效的;如果是应答报文,序号和确认序号都是有效的
  • 应答报文的序号是另一套编号体系,和传输数据的序号是不一样的
  • 应答报文默认情况下是不携带数据的


相关实践学习
通过Ingress进行灰度发布
本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
相关文章
|
6月前
|
网络协议 Python
TCP传输的三次握手、四次挥手策略是什么
TCP传输的三次握手、四次挥手策略是什么
47 0
|
2月前
|
存储 网络协议 Linux
三次握手时,客户端发送的 SYN 报文为什么会被丢弃?
三次握手时,客户端发送的 SYN 报文为什么会被丢弃?
84 12
|
5月前
|
网络协议 NoSQL 算法
TCP协议:超时重传、流量控制、keep-alive和端口号,你真的了解吗?
【6月更文挑战第2天】本文探讨了TCP协议的关键机制,包括超时重传计算(基于SRTT和RTT),流量控制(使用滑动窗口适应接收方处理能力),TCP keep-alive(通过定期探测保持连接活性),以及端口号的作用(区分不同服务和应用)。这些内容对于理解TCP的工作原理和面试准备至关重要。
113 1
|
5月前
|
网络协议
TCP传输的三次握手四次挥手策略
TCP传输的三次握手四次挥手策略
31 0
|
6月前
|
网络协议 网络架构
什么是TCP重传?
TCP(Transmission Control Protocol)是一种可靠的、面向连接的传输层协议,用于在网络上可靠地传输数据。在TCP中,数据通过数据包进行传输,而TCP重传是TCP协议中的一个重要机制,用于确保数据的可靠传输。
45 1
|
6月前
|
网络协议 Linux
TCP中两种保活方式
【4月更文挑战第7天】两种保活方式:Keep Alive和心跳包
|
6月前
|
网络协议 算法 网络性能优化
|
缓存 网络协议 算法
网络基本功:http报文及TCP拥塞控制机制
网络基本功:http报文及TCP拥塞控制机制
|
网络协议
TCP的三次握手以及以段为单位发送数据【TCP原理(笔记二)】
TCP的三次握手以及以段为单位发送数据【TCP原理(笔记二)】
104 1
TCP的三次握手以及以段为单位发送数据【TCP原理(笔记二)】
|
运维 网络协议 Linux
用了TCP协议,就一定不会丢包吗? 2
用了TCP协议,就一定不会丢包吗?
202 0