【计算机网络】面试必问TCP十大机制

news/2024/10/7 19:24:48 标签: tcp/ip, 网络, 服务器

  1. TCP协议的报文格式

  说明:

  TCP 报文格式主要分为两部分:TCP 报文头部和数据部分。以下是对各字段的详细解释:

TCP 报文头部

  • 源/目的端口:各占用16位。表示数据从哪个进程发送,发送到哪个进程去。
  • 序号字段:占 32 位。用于标识发送端发送的字节流中的每一个字节的顺序编号。
  • 确认序号:占 32 位。表示接收端期望接收的下一个字节的序号,是对发送端的一种确认机制。例如,接收端收到序号为 1000 到 1999 的数据段后,发送的确认报文中确认序号字段的值应为 2000,表示已成功接收到 1000 到 1999 字节,期望下一个字节为 2000。
  • 首部长度:占 4 个字节。表示 TCP 报文头部的长度。 保留字段:占 6 位。为 TCP 将来的发展预留空间,目前必须全部为 0。
  •  标志字段:占 6 位,包含六个控制位:
  • URG:当 URG = 1 时,表示紧急指针字段有效,用于指示紧急数据。紧急数据可以绕过正常的数据流,优先传输和处理。
  •  ACK:当 ACK = 1 时,表示确认序号字段有效。在 TCP 建立连接后,ACK 标志位通常为 1,表示对收到的数据进行确认。
  •  PSH:当 PSH = 1 时,表示接收端应立即将数据交付给上层应用,而不要等到整个缓存都填满了之后再向上交付。
  • RST:当 RST = 1 时,表示连接出现严重差错,必须释放连接,然后再重新建立传输连接。
  •  SYN:在建立连接时使用,当 SYN = 1 而 ACK = 0 时,表示这是一个连接请求报文段;对方若同意建立连接,在发回的报文段中使 SYN = 1 和 ACK = 1。
  • FIN:当 FIN = 1 时,表示发送端的数据已发送完毕,请求释放传输连接。 
  • 窗口大小:占 16 位。用于流量控制,表示接收端可接收的数据量,以字节为单位。发送端根据窗口大小调整发送的数据量,以避免接收端缓冲区溢出。
  •  检验和:占 16 位。用于确保数据的完整性。发送端计算并填充检验和字段,接收端收到报文后再进行计算,比较结果是否一致。如果不一致,表示数据在传输过程中发生了错误。 
  • 紧急指针:占 16 位。仅在 URG 标志置 1 时有效,指示在报文中的紧急数据的结束位置。

  2. 数据部分:可变长度,包含上层应用程序的数据。TCP 头部后面的数据部分是上层应用程序传递给 TCP 的数据,例如网页内容、文件数据等。

  1. 可靠传输机制

  注意:可靠并不意味着消息能够百分之百发给接收方,而是尽可能的把消息传输过去,即使没有成功发送,最气码发送方要能够知道。

 确认应答机制

  确认应答机制是保障TCP可靠传输最核心的机制之一。主机A给主机B发了个消息,主机B收到消息之后,就会给主机A返回一个应答报文(ACK),此时,主机A收到应答之后,就知道自己发送的数据已经成功到达主机B了。如下图所示:

  网络环境十分复杂,可能会出现后发先至的情况。如下图所示:

  说明:此处我可能连续发送多条消息,我发第二条消息的时候,不需要等待第一个消息的回应,女神收到消息之后立马就会回复我。在这次网络通信中,原本的意思是这样的:我说:女神女神我请你吃麻辣烫好不好;女神说:好啊好啊;我说:女神可以做我女朋友吗?女神说:滚蛋。此时引发了歧义。

  结论:网络出现后发先至的现象是客观存在的,无法避免的,因此,应答报文(ACK)到达的顺序也是有可能发生变化的。此时就要考虑如何规避这种顺序错乱带来的歧义。

  解决后发先至的方案:给传输的数据和应答报文都进行编号。如下图所示:

  当引入序号之后,此时就不怕顺序乱了;即使顺序乱了,也可以通过序号来判断当前应答报文是针对哪个数据进行的。  

  注意:上图中的1,2只是为了说明可以采取编号的方式来解决后发先至的问题,TCP的序号并不是按照1,2来编号的,而是按照字节来编号。

  主机A给主机B发送一个数据报,主机B要返回一个确认应答的数据报给主机A 。
实现的方式:序号和确认序号保证了响应应答针对的是哪一条消息的应答。

  说明:

  1:主机A发送的数据是基于TCP报头中的 " 32位序号 "来保存的,一个字节对应一个序号。

  2:确认应答的数据是基于TCP报头中的 " 32位确认序号 " 来保存的,此时,ACK标志位为1。

  3:确认序号的取值,是收到的数据的最后一个字节的序号 + 1。

  4:接收者返回确认序号,说明该确认序号之前的数据被接收者全部接收到。

  小结:TCP可靠传输的能力,最主要通过确认应答机制来保证的,通过应答报文,就可以让发送方清楚的知道数据传输是否成功。进一步的引入了序号和确认序号。


 

 超时重传机制

  讨论确认应答的时候,只是讨论了顺利传输的情况,如果丢包了呢?

  丢包分为两种情况:一种是发送端发送的数据没有到达接收端,一种是ACK丢了。因此,TCP引入了重传机制,在丢包的情况下,发送端就需要重新发送数据报。

  这次传输到底是丢包了,还是ACK走得慢,还在路上呢?针对这一问题,TCP引入了一个时间阈值,发送方发了一个数据之后,就会等待ACK,开始计时,如果在时间阈值内,还没有收到ACK,此时不管ACK是丢了,还是在路上,都统一认为是丢包了。

  

  网络环境十分复杂,可能存在丢包情况,超过一定时间,主机A还没有收到ACK,主机A就需要重新发送数据报。

  数据丢了的情况:如下图所示:

   ACK丢了的情况:如下图所示:

  问题:对于主机B来说1-2000就收到了两次,重复的数据怎么办?

  TCP对于这种重复数据的传输,会进行去重处理。TCP存在一个接收缓冲区(是一个存储空间,接收方操作系统内核里的一段内存),主机B收到主机A的数据,其实就是主机B的网卡读到了数据,然后把这个数据放到主机B对应的接收缓冲区中;此时根据数据序号,TCP很容易识别当前接收缓冲区里的这两条数据是否是重复的。如果重复,直接把后来的这份数据直接丢弃;保证应用程序进行read操作的时候,数据一定是不重复的。

  问题:如果重传的数据丢了,该怎么办?

  丢包本就是一件小概率事件,此时重传的数据也发生了丢包,概率更小,TCP如果进行重传多次依然丢包,此时网络势必出现了重大故障。

  小结1:

  由于去重和重新排序机制的存在,发送方只要发现ACK没有按时到达,就会重传数据。即使重复了,顺序乱了,接收方都能够进行有效的处理。(去重和排序都依赖于TCP报头的序号)。

  小结2:

  可靠传输是TCP最核心的部分,TCP可靠传输就是通过确实应答和超时重传来进行体现的,其中确认应答描述的是数据顺利传输的情况;超时重传描述的是传输出现问题的情况;两者相互配合,共同支撑整体的TCP可靠性。

连接管理机制(三次握手,四次挥手)

  在发送数据之前,要先通过三次握手建立连接;不需要发送数据了,通过四次挥手断开连接。

  建立连接(三次握手):通信双方各自要记录对方的信息,彼此之间要相互认同。

  如图所示:

   说明:

  1:客户端向服务端发送SYN,申请建立连接。
  2:服务端返回ACK(第一次SYN的应答)和SYN,申请建立客户端到服务端的连接。
  3:客户端收到数据,TCP状态设置为ESTABLISHED,表示两端连接建立完成,并且发ACK。      4:服务端收到数据,状态置为ESTABLISHED,表示接收端到发送端的连接建立完成。

  小结:

  所谓的三次握手,本质上是四次交互。通信双方,各自要向对方发起一个建立连接的请求,同时,在各自向对方回应一个ACK,进行了四次交互。中间的两次交互,是可以合并成一次交互的,因此构成了三次握手。

  问题:中间这两次交互,不合并可以吗?

  一定要进行合并。封装分用两次,成本比一次高。

  问题:三次握手中的中间两次为什么可以合并?四次挥手就不行呢?

  三次握手能够合并,因为中间这两次属于同一时机触发。三次握手在交互过程中,是在纯内核中完成的,服务器的系统内核收到客户端的syn之后,就会立即发送ack和syn。

  结论:三次握手主要是为了检查当前网络状况是否满足可靠传输的基本条件,同时也是在检测通信双方的发送能力和接收能力是否正常 。

四次挥手 

  说明:

  1:客户端发送FIN到服务端,申请关闭客户端到服务端的连接。

  2:服务端收到FIN状态置为CLOSE_WAIT,并返回ACK。

  3:服务端发送FIN到客户端,申请关闭服务端到客户端的连接(服务端程序执行socket.close)

  4:客户端收到FIN返回ACK应答,并进入TIME_WAIT时间等待状态,客户端等待一段时间后,状态置为CLOSED,服务端收到应答后,状态置为CLOSED。

思考:

  为什么服务端不将ACK和FIN合并一起发送,形成三次挥手呢?
  答:主要是ACK和FIN的发送时机不同,ACK是操作系统内核响应的(立即执行),而此时服务端还可能在继续发送数据,待处理完数据后由程序调用close方法后才发送FIN。

  为什么客户端要等待一段时间(TIME_WAIT)状态才置为CLOSED,而不直接将状态置为CLOSED?

  答:如果客户端给服务端的ACK丢包后,服务端得重新给客户端发送FIN,此时客户端给服务端ACK,所以此时状态不能置为CLOSED,得等待一段时间(2MSL,MSL为网络上任意两点传输的最大时间)确保服务端收到客户端的应答 。(如果最后一个ACK丢了,站在服务器的视角来看,服务器不知道是对方的ACK丢了,还是自己发的FIN丢了,此时统一视为FIN丢了,需要进行重传处理。既然服务器可能需要重传FIN,客户端就需要针对这个重传的FIN进行ACK响应;如果彻底把连接释放了,这样ACK就无法进行了,因此使用TIME_WAIT状态保留一定的时间,就是为了能够处理最后一个ACK丢包的情况,能够在收到重传的FIN之后,进行ACK响应。)。

滑动窗口

  对于基本确认应答的的情况来说,每次发送一个数据,都需要等待ACK到了再发下一个。

  如图所示:

  滑动窗口的本质就是不等待的批量发送一组数据,然后用一份时间来等待一组数据的多个ACK。如图所示:

  把不需要等待,就能直接发送的数据的最大的量,称为窗口大小。在这个图中窗口大小是4000。

  注意:当批量发送了窗口大小数据之后,发送方就要等待ACK了,需要注意的是,不是等待所有ACK到达,才继续往下发,而是等待到一个ACK,就继续往下发一条数据。 

  如图所示:

如果出现了丢包,如何确保可靠传输?

  • 情况一:数据已经收到,返回的ACK丢包

  部分ACK丢了不要紧,因为可以通过其他的确认序号进行确认 。

  • 情况二:发送数据的时候就已经丢包  

  对这个图进行说明:由于1001-2000的数据丢包了,接下来的2001-3000到达主机B之后,B给A返回的ACK确认序号仍然是1001,这个1001的含义可以理解为,B向A在索要1001之前的数据;此时A重新发送1-1000的数据给B,发送成功了,此时B给A发送7001。(这个7001可以从两个角度去理解:1:B告诉A7001之前的数据我已经收到。2:B告诉A,你接下来发送的数据应该是7001-8000)。 

  上述重传的方式叫做快速重传(只重传丢失的数据),这个快速重传可以视为是超时重传机制在滑动窗口下的变形。如果当前传输的数据密集,按照滑动窗口的方式来传输,此时按照快速重传来处理丢包;如果当前传输的数据稀疏,按照超时重传机制进行处理。

流量控制 

  流量控制是一种干预发送窗口大小的机制。一般来说,窗口越大,传输的效率就越高(一份时间等到的ACK就越多),但是窗口也不能无限大。原因如下:

1.完全不等待ack,可靠性不能得到保障。

2.窗口太大,会消耗太多的系统资源。

3.发送速度太快,接收方处理不过来。

  接收方的处理能力,是一个很重要的约束依据,发送方发送数据的速度,不能超出接收方的处理能力。流量控制需要做的工作就是,根据接收方的处理能力,协调发送方的发送速率。

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

 

  解释说明:TCP中采用接收缓冲区里的剩余容量作为衡量发送方发送速率的指标。每次主机A给主机B发送了数据之后,主机B就需要计算一下自己的接收缓冲区里的剩余空间,然后把这个值通过ack报文返回给主机A;主机A根据这个值来决定接下来发送的速率是多少(窗口大小)。

  注意:由于接收方的接收缓冲区剩余空间是一直在动态变化的,所以每次返回ack带回来的数值(窗口大小)都在变化,发送方也就在动态的调整自己的发送速率。当窗口大小为0,发送方就要暂停发送,暂停发送的等待过程中,会给B定期发送窗口探测报文,这个报文不携带具体的业务数据,只是为了触发ack查询窗口大小。如下图所示:

拥塞控制

  流量控制和拥塞控制共同决定发送方的窗口大小是多少。流量控制考虑的是接收方的处理能力;拥塞控制描述的是传输过程中中间节点的处理能力。

如图所示:

  在前面,我们讨论了接收方的处理能力,和发送方的发送速率,但没有讨论中间节点,那么怎么去衡量中间节点对数据的处理能力呢?

  中间节点的处理能力不好量化,TCP中采取的策略是通过试验的方式,来测试出一个合理的值。

如图所示:

解释说明:

  从第0轮开始,窗口大小是一个单位,发现传输的数据没有丢包,就扩大窗口。第一轮2,第二轮4,第三轮8......依次类推,成指数级增长的状态;当增长速率达到阈值之后,从指数增长变成线性增长,增长的前提是不丢包。在接下来,当传输过程中一旦丢包,说明此时发送的速率已经接近网络的极限了。 此时就把窗口大小一下缩成很小的值,在重复指数增长和线性增长的过程。

意义:

  拥塞窗口不是一个固定的数值,而是一直动态变化,随着时间的推移,逐渐达到一个动态平衡的过程,这样做既把问题解决了,同时随着网络的动态的变化而动态变化。拥塞控制和流量控制的窗口,共同决定了发送方实际的发送窗口。

延时应答

  延时应答就是主机B收到数据之后,不要立即返回ACK,而是稍微等一会在返回。在等待的时间里,接收方的应用程序,就能把接收缓冲区的数据先处理一下,这样接收缓冲区的空间就大了一点。延时应答要做的的就是,在接收方能处理得了的前提下,尽可能的把窗口放大一点。

如图所示:

解释说明:

  延时应答采取的策略:在滑动窗口下,ack不在每一条数据都返回,此处是隔一条返回一个ack。

捎带应答 

  为了提高效率,在延时应答的基础之上引入捎带应答。客户端服务器最典型的模型就是"一问一答",如下图所示:

解释说明:

  B返回的ack和B业务上的响应,它们属于不同时机。由于TCP存在延时应答机制,就导致等待ack的过程中,B就要给A发送业务数据了,此时,就可以让业务数据捎上这个ack一起返回给A。

  本来是不同时机,在延时应答的作用下,可能就成为相同的时机,此时就会合并,如图所示:

粘包问题

  TCP是面向字节流的,一次读取一个字节,多个字节都是可以的。这样势必会导致一次读到的数据,可能是半个应用层数据报,可能是一个应用层数据报,也可能是多个应用层数据报。

解决方案:

1:约定好分隔符。

2:约定每个包的长度。 

异常情况


http://www.niftyadmin.cn/n/5693264.html

相关文章

前端知识汇总(持续更新)

见:GitHub - eHackyd/Front-End: 前端知识汇总 包含:html,css,js,ts等等(语法使用实例)

Linux更改固定IP地址

1.VMware里更改虚拟网络 一: 二: 三:确定就好了 2.修改Linux系统的固定IP 一:进入此文件 效果如下: 执行以下命令: 此时IP已更改 3.远程连接 这个是前提!!! 更改网络编辑器后网络适配器可能会修改,我就是遇着这个,困住我了一会 一:可以以主机IP对应连接 连接成功 二:主机名连…

df命令输出的详细解释

理解 df -h 命令的输出对于有效管理和监控 Ubuntu 系统的磁盘空间至关重要。df(Disk Free)命令用于显示文件系统的磁盘空间使用情况,而 -h 选项使输出以“人类可读”的格式(如 GB、MB)显示,便于理解。 示例…

阿里巴巴_java开发规范手册详解

1、 命名风格 1.1、开始结尾规范 代码中的命名均不能以下划线或美元符号开始,也不能以下划线或美元符号结束。 反例: _name, $name, __name 1.2、严禁使用拼音与英文混合及中文的方式 代码中的命名严禁使用拼音与英文混合的方式,更不允许…

水上基础设施检测系统源码分享

水上基础设施检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Computer Vis…

HCIE《网络括谱图》

企业园区网 终端>接入>汇聚>核心>出口区(防火墙)>互联网

【java】数据类型与变量以及操作符

各位看官:如果您觉得这篇文章对您有帮助的话 欢迎您分享给更多人哦 感谢大家的点赞收藏评论,感谢您的支持!!! 目录 一.字面变量: 二:数据类型 1.1:int类型:&#xff0…

Cilium-实战系列-(二)Cilium-Cluster Mesh-服务全局负载均衡

本篇博客只讲一件事情: 1、如果使用Cilium的能力将两个k8s集群逻辑上成1个集群并且使得应用可以全局负载均衡。 一、Cilium-Cluster Mesh 1、就是可以把多个k8s集群逻辑上为1个大集群并且上面的业务可以负载均衡。 2、可以在集群之间跑网络策略。 二、Cluster Mesh-使…