TCP机制|确认应答、超时重传和连接机制

发布时间 2023-11-22 16:20:42作者: 司丝思

TCP全称Transmission Control Protocol,即传输控制协议,TCP对数据传输提供的管控机制,主要体现在两个方面:安全和效率。

 一、TCP协议格式

16位源/目的端口号:发送方的端口号,接收方的端口号

32位序号:TCP数据报携带的数据的起始序号

32位确认序号:期待对方发送的数据是从哪一个序号开始发送

4位首部长度:描述了TCP报头的长度,4位首部长度的单位是4字节,比如首部长度的值是6,那TCP报头的长度就是24字节

保留(6位):先保留6位,为以后的扩展考虑。如果后续TCP需要引入一些新的功能,就可以使用保留的6位字段

6个标志位:

  • URG:紧急标志位
  • ACK:确认标志位
  • PSH:发送数据标志位,提示接收端应用程序立刻从TCP缓冲区把数据读走
  • RST:重置连接标志位,当无法识别对方发来的连接请求时,就会使用RST标志位。把携带RST标识的称为复位报文段
  • SYN:请求连接标志位,把携带SYN标识的称为同步报文段
  • FIN:断开连接标志位,携带FIN标识的为结束报文段

16位窗口大小:告知发送方自己接收数据能力的大小,这个值是动态变化的

16位检验和:检验发送的数据是否失真

16位紧急指针:标识哪部分数据是紧急数据

选项:选项之前部分的长度是固定的20字节,首部长度减去20字节就是选项部分的长度。选项相当于是对TCP报文的一些属性进行解释说明的

二、TCP的机制

TCP的机制有很多,这里介绍10个核心机制

1、确认应答机制

确认应答机制是发送方确保自己的数据要被对方收到。发送方发出数据以后,接收方要给发送方一个回复,确认自己已经收到数据了,这样的回复称为ACK,确认应答报文。而发送方收到确认回复之后也知道自己的数据被对方收到了。

发送方可以同时发送多条数据,接收方根据收到的消息给出回复,但存在“后发先至”问题,接收方收到的数据顺序被打乱,这可能引起严重的歧义。例如下面这种情况,双方最终会造成误解。

针对“后发先至”问题,TCP的解决办法是给传输的数据和应答报文都进行编号。TCP是面向字节流传输的,在编号的时候是给每个字节都编上序号,假设每次传输1000个字节,那么第一个字节的序号就是1,第二个字节的序号就是2...最后一个字节的序号就是1000。由于这1000个字节是属于同一个TCP数据报的,TCP报头就只记录第一个字节的序号。

上述说到的编号就需要用到TCP报文格式中的32位序号和32位确认序号,发送方利用32位序号记录发送的数据的第一个字节的序号,接收方读完数据之后,返回给发送方32位确认序号,即告之对方下一个数据的第一个字节应该从哪个序号开始。在TCP协议中,每一条数据都是有序号的,包括应答报文,一条数据是否是应答报文就要根据ACK标志位来确定,如过ACK为1那就是应答报文了,如果为0则不是应答报文了。

 TCP的可靠传输主要就是通过确认应答机制来保证的,通过应答报文就能让发送方清楚的知道传输是否成功,引入32位序号和32位确认序号进一步确保对多条数据有效的传输。

2、超时重传

确认应答机制讨论的前提是每条数据都能顺利传输的情况,那么在丢包的情况下该如何应对呢,应对方法就是超时重传。丢包存在两种情况,发的数据丢包了,返回的ACK丢包了,不管是哪种情况,只要没有收到ACK,都会在到达某个时间阈值之后进行重传。

发的数据丢包的情况下,发送端过了某个时间阈值之后会重新传输相同的数据。

 ACK丢包的情况下,其实接收端已经收到发送端传输过来的数据,发送端再次发送相同的数据过来该如何处理呢?TCP有一个特殊的处理功能,去重,TCP存在一个“接收缓冲区”的存储空间,接收端会将读到的数据放到对应的缓冲区,根据数据的序号,TCP就能识别是否有两条重复的数据,如果重复就把后面的这条数据给丢弃了。

那么,TCP是否会进行无限次的重传?

数据丢包是一个概率事件,假设一条数据在传输的过程中丢包的概率是5%,传输成功的概率是95%,那么第一次传输丢包,第二次重传也丢包的概率是5%*5%=0.25%,第三次重传也丢包的概率可以忽略不计,在实际情况中,丢包的概率是一个非常小的数字,而上述假设的5%已经是一个很大的数字了,如果连续多次重传还是丢包的情况下,那么就要考虑是否是网线断了或是其他情况了。关于具体重传的次数,有很多种说法,这里就不讨论了。

3、连接管理机制(安全机制)

TCP是面向有连接的,要在连接的情况下进行数据的传输,通常情况下要进行三次握手建立连接,四次挥手断开连接。

1)建立连接(三次握手)

举个生活中常见的例子 : 打电话

我:喂,XXX能听到吗?

XXX:哎,能听到,你能听到吗?

我:我也能听到

上述例子中的三次对话是为了确保双方接下来能够正常通话,TCP三次握手也是这个道理

 SYN是请求连接标志位,这里简单描述TCP三次握手的过程,由客户端主动发起请求连接报文,此时TCP报头的SYN=1,并选择一个初始序号seq = x,表示当前发送的数据从x开始编号。服务器收到发来的连接请求会返回一条报文,报头包含请求连接SYN = 1,确认应答(同意连接)ACK = 1,并将自己选择的初始序号seq = y发送过去,ack = x+1表示对方下一条发来数据从x+1开始编号。客户端收到服务器发来的报文之后,会回复一个确认应答报文,报头的ACK = 1,seq = x+1,表示当前传输的数据从x+1编号,ack = y+1,表示对方下一条发来的数据从y+1开始编号。

为什么要进行三次握手?

大家是否有这样的疑惑:为什么是三次握手建立连接呢?两次握手、四次握手是否可行呢?首先来看看每次握手的作用:

第一次握手,服务器的接收能力正常,客户端的发送能力正常,但客户端并不知道自己的发送能力和接收能力是否正常,这就需要第二次握手;

第二次握手,客户端的发送能力正常,接收能力正常,服务器的发送能力正常,但从服务器的角度来看,不确定自己的发送能力是否正常,客户端的接收能力是否正常,

所以就要进行第三次握手;

第三次握手,服务器发送能力正常,客户端的接收能力正常。

那么如果是两次握手就建立连接的情况下,当服务器将第二次的握手的信息发出去之后,默认连接已经建立,并且开辟空间资源等待接收数据。但如果第二次握手的信息丢包了呢,服务端认为二次握手已经完成,建立了连接,而客户端呢,由于什么也没有收到,所以会进行超时重传,当服务器又收到连接请求,认为有新的客户端发起连接,于是同意连接请求,并开辟空间资源等待接收数据,如果出现大量上述情况,便会造成客户端的崩溃。

四次握手是否可行呢?理论上四次握手是可行的,但是没有必要。将第二次握手的SYN和ACK分开发送,就构成了四次握手,那么TCP要进行两次分装分用,封装分用两次的成本要比一次的成本高很多。

到这里,你是否有这样的疑问,如果第三次握手的数据丢包了呢?

从客户端的角度来看,ACK已经发出去了,连接已经建立了,可以传输数据了;但从服务器的角度来看,没有收到ACK,连接就还没有建立,这种情况下,服务器这端会进行超时重传,重传一定次数之后,如果还没有收到客户端发送的ACK,那么服务器就会关闭连接,在这个过程中如果收到客户端传输的数据,服务器会响应一个错误。

2)断开连接(四次挥手)

四次挥手过程:

FIN是断开连接标志位。

三次握手就可以建立连接,为什么四次挥手才能断开连接?

FIN的发起不是由操作系统的内核发起的,而是由应用程序调用socket的close()方法或退出进程触发的,而ACK是由内核发出的,在收到FIN之后会立即返回ACK。SYN和ACK是由内核控制的,是在同一时机发出的,因此可以打包为一个数据报,而FIN是应用程序调用close()或退出进程才触发的,与ACK的发送可能不在同一个时机,当然ACK和FIN的发送也可能是在同一时机,这主要就看代码是如何写的了,此时系统可能就打包成一个数据报一起发送了。