TCP如何保证可靠性

简介: TCP如何保证可靠性

校验和


TCP检验和的计算与UDP一样,在计算时要加上12byte的伪首部,检验范围包括TCP首部及数据部分。

计算方法为:在发送方将整个报文段分为多个16位的段,然后将所有段进行反码相加,将结果存放在检验和字段中,接收方用相同的方法进行计算。


如果接收方校验和与发送方不一致,那么数据一定传输有误。但是如果接收方比对校验和与发送方一致,数据不一定传输成功。


序列号与确认号


序列号Seq:TCP将每个字节的数据都进行了编号,一般序列号Seq为将要传输的数据的第一个编号

确认号Ack:TCP收到数据后,期望下一次收到数据的第一个编号

序列号的作用:

  1. 保证可靠性,通过Ack可以判断接收方是否少接收数据
  2. 保证数据的按序到达,因为每个字节的数据都有编号
  3. 提高效率,可实现多次发送,一次确认
  4. 去除重复数据,由于网络阻塞加上超时重传机制,可能发送了两次相同的数据,接收方丢弃第二次发来的数据


确认号的作用:

  1. 可靠的数据传输,Ack的值表示这个值之前的数据都已经按序到达了
  2. 延迟确认,如果连续收到两个TCP包,并不一定需要Ack两次,只要回复最终的Ack就可以了,可以降低网络流量。



超时重传


因为有确认应答与序列号机制,在发送方发送一部分数据后,会等待接收方发送的ACK报文,并解析ACK报文,判断数据是否传输成功。如果发送方发送完数据后,迟迟没有等到接收方的ACK报文,这该怎么办呢?而没有收到ACK报文的原因可能是什么呢?


首先,发送方没有介绍到响应的ACK报文原因可能有两点:


  1. 数据在传输过程中由于网络故障导致丢包,接收方没有接收到数据
  2. 接收方接收到了数据,但是ACK报文响应却由于网络故障导致丢包


超时重传:发送方在发送完数据后等待一个时间,时间到达没有接收到ACK报文,那么对刚才发送的数据进行重新发送。如果是第一个原因,接收方收到二次重发的数据后,便进行ACK应答。如果是第二个原因,接收方发现接收的数据已存在(判断存在的根据就是序列号,所以上面说序列号还有去除重复数据的作用),那么直接丢弃,仍旧发送ACK应答。


那么发送方发送完毕后等待的时间是多少呢?

由于TCP传输时保证能够在任何环境下都有一个高性能的通信,因此这个最大超时时间(也就是等待的时间)是动态计算的。


在Linux中超时以500ms为一个单位进行控制,每次判定超时重发的超时时间都是500ms的整数倍。重发一次后,仍未响应,那么等待2500ms的时间后,再次重传。等待4500ms的时间继续重传。以一个指数的形式增长。累计到一定的重传次数,TCP就认为网络或者对端出现异常,强制关闭连接。

滑动窗口 (TCP流量控制)

接收端在接收到数据后,对其进行处理。如果发送端的发送速度太快,导致接收端的结束缓冲区很快的填充满了。此时如果发送端仍旧发送数据,那么接下来发送的数据都会丢包,继而导致丢包的一系列连锁反应,而TCP根据接收端对数据的处理能力,决定发送端的发送速度,这个机制就是流量控制。


在TCP协议的报头信息当中,有一个16位字段的窗口大小。在介绍这个窗口大小时我们知道,窗口大小的内容实际上是接收端接收数据缓冲区的剩余大小。这个数字越大,证明接收端接收缓冲区的剩余空间越大,网络的吞吐量越大。接收端会在确认应答发送ACK报文时,将自己的即时窗口大小填入,并跟随ACK报文一起发送过去。而发送方根据ACK报文里的窗口大小的值的改变进而改变自己的发送速度。如果接收到窗口大小的值为0,那么发送方将停止发送数据。并定期的向接收端发送窗口探测数据段,让接收端把窗口大小告诉发送端。


窗口大小不受16位窗口大小(64k)限制,在TCP首部40字节选项中还包含一个窗口扩大因子M,实际窗口大小是窗口字段的值左移M位



拥塞控制

直接看别人的,不是重点


三次握手(重点)


TCP协议为什么需要三次握手?

主要原因是为了防止旧的重复连接引起连接混乱问题


比如在网络环境比较复杂的情况,客户端可能会连续发送多次请求。如果只设计成两次握手的情况,服务端只能一直接收请求,然后返回请求信息,也不知道客户端是否请求成功。这些过期请求的话就会造成网络连接的混乱。


所以设计成三次握手的情况,客户端在接收到服务端SEQ+1的返回消息之后,就会知道这个连接是历史连接,所以会发送报文给服务端,告诉服务端。


所以TCP设计成三次握手的目的就是为了避免重复连接。为了节省资源,三次握手就可以符合实际情况,所以就没必要设计成四次握手、五次握手等情况。

建立过程为:


  1. server首先建立传输控制块TCB,进入LISTEN(收听)状态,等待用户的连接请求。如有,则建立连接。(c语言中为server端调用socket函数、bind函数和listen函数的过程)
  2. client建立传输控制块TCB,然后向server发送连接请求报文段,报文段中首部的同步位SYN=1,同时选择一个序列号seq=x(随机),TCP规定SYN报文段不携带数据,但要消耗一个序列号。然后A进入SYN-SENT(同步已发送)状态。(c语言中为client端调用socket函数和connect函数的过程)
  3. server收到请求后,如同意建立连接,就向client发送确认报文段。此时SYN=1、ACK=1,确认号ack=x+1,同时选择一个序列号seq=y(随机),这个报文也不携带数据,但要消耗一个序列号。然后B进入SYN-RCVD状态(同步收到)。
  4. client收到server的确认后,还要向server发送确认。确认报文段的ACK=1,确认号ack=y+1,seq=x+1。TCP规定,ACK报文段可以携带数据,而如果不携带数据则不消耗序列号,此时下一个报文段的序列号仍为seq=x+1。这时,连接就建立成功了,A进入ESTABLISHED状态(已建立连接状态)。
  5. 当server收到client的确认后,也进入ESTABLISHED状态,此时就可以进行数据传输了。

四次挥手(重点)


1.为什么连接的时候是三次握手,关闭的时候却是四次握手?


因为当server端收到client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。

但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文(否则可能触发超时重传),告诉client端,“你发的FIN报文我收到了”。只有等到我server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。


2.为什么TIME_WAIT状态需要经过2MSL(最大报文段生存时间)才能返回到CLOSE状态?


虽然按道理,四个报文都发送完毕,我们可以直接进入CLOSE状态了,但是我们必须假象网络是不可靠的,有可能最后一个ACK丢失。所以TIME_WAIT状态就是用来重发可能丢失的ACK报文。在Client发送出最后的ACK回复,但该ACK可能丢失。server如果没有收到ACK,将不断重复发送FIN片段。所以Client不能立即关闭,它必须确认server接收到了该ACK。Client会在发送出ACK之后进入到TIME_WAIT状态。client会设置一个计时器,等待2MSL的时间。如果在该时间内再次收到FIN,那么client会重发ACK并再次等待2MSL。所谓的2MSL是两倍的MSL(Maximum Segment Lifetime)。MSL指一个片段在网络中最大的存活时间,2MSL就是一个发送和一个回复所需的最大时间。如果直到2MSL,Client都没有再次收到FIN,那么Client推断ACK已经被成功接收,则结束TCP连接。


在连接释放时,连接的两方都要同意才能够释放成功


当client的数据传送完后,就可以向其TCP发起连接释放了,此后停止再发送数据,主动关闭TCP连接。首先client向server发送一个FIN报文段,报文段首部FIN=1,序列号seq=u(u为最后传送的数据的序列号加1),然后client进入FIN-WAIT-1(终止等待1)状态。FIN报文段不能携带数据,但要消耗一个序列号。


server收到释放连接的报文段后即发出确认报文段,报文首部ACK=1,ack=u+1,seq=v(v等于server前面传送过的数据的序列号加1),然后B进入CLOSE-WAIT(关闭等待)状态。这时从client到server这个方向的连接就释放了,TCP连接就处于半关闭状态。(注意:此后client不能主动向server发送数据,但是可以发送确认报文段,也就是说client仍要接收来自server的报文,因为从server到client这个方向的连接还没有关闭)


当client收到server的确认报文后,就进入FIN-WAIT-2(终止等待2)状态,等待server发出的连接释放报文段。


当server的数据发送完毕后,其应用进程就通知TCP释放连接。server向client发送FIN报文,报文段首部FIN=1,ack=u+1(重复发送上一次已经发送过的确认号),seq=w(w为server最后发送报文段的序列号加1)。然后B进入LAST-ACK(最后确认)状态,等待client的确认。


client在接收到server的连接释放报文后,必须进行确认。client向server发送的确认报文段中报文首部ACK=1,ack=w+1,seq=u+1。然后client进入TIME-WAIT(时间等待)状态(如果无差错,此状态时间为2MSL),注意,此时TCP连接还没有释放掉,必须经过TIME-WAIT设置的时间2MSL后,client撤销相应的传输控制块TCB,才进入CLOSED状态,结束了此次TCP连接。MSL叫做最长报文段寿命,RFC793建议设为2分钟,但在现在实际网络情况中,常用值有三种:30秒,1分钟,2分钟。必须要在client进入CLOSED状态后才能开始建立下一个新的连接。


server收到client的确认报文后,也进入CLOSED状态,撤销相应的传输控制块TCB,此时,TCP连接全部断开。


这样TCP四次挥手完成。


相关实践学习
通过Ingress进行灰度发布
本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
目录
相关文章
|
7月前
|
网络协议 算法 网络性能优化
【计算机网络】TCP 如何实现可靠传输
【计算机网络】TCP 如何实现可靠传输
88 6
|
7月前
|
网络协议 算法 网络性能优化
|
7月前
|
网络协议 前端开发 Java
为何要3次握手?TCP协议的稳定性保障机制
为何要3次握手?TCP协议的稳定性保障机制
为何要3次握手?TCP协议的稳定性保障机制
|
7月前
|
缓存 网络协议 物联网
UDP的可靠性传输
UDP的可靠性传输
206 1
|
7月前
|
监控 网络协议 算法
TCP 拥塞控制对数据延迟的影响
TCP 拥塞控制对数据延迟的影响
|
7月前
|
缓存 网络协议 算法
UDP的可靠性传输2
UDP的可靠性传输2
91 0
|
存储 缓存 网络协议
TCP vs UDP:揭秘可靠性与效率之争
在网络通信中,TCP和UDP是两种最常用的传输层协议。本文将深入探讨TCP和UDP之间的区别,包括连接方式、服务对象、拥塞控制、流量控制和首部开销等方面,帮助读者在不同应用需求下选择适合的协议。无论你是技术爱好者还是网络工程师,这篇文章定能帮助你了解并应用TCP和UDP的差异,提升你的网络传输效率和可靠性。
1306 1
|
网络协议 算法 网络性能优化
TCP为什么是可靠的(怎么保证有效传输的)?
TCP为什么是可靠的(怎么保证有效传输的)?
657 0
|
缓存 监控 网络协议
2.6 TCP与UDP的可靠性传输
2.6 TCP与UDP的可靠性传输
125 0
|
网络协议 Linux 网络性能优化
TCP 协议如何保证传输的可靠性
TCP 协议如何保证传输的可靠性
224 0