TCP协议全称为传输控制协议,是一种面向连接的、可靠的、基于字节流的传输层通信协议。与UDP协议最大的不同是,其会保证消息传输的可靠性。
TCP协议格式
源端口:标识发送进程。
目的端口:标识目的进程
32位序号:标识从 TCP 发送端向 TCP 接收端发送的数据字节流,表示报文段中的第一个数据字节的序号。
32位确认序号:接收端表示接收方期望收到的下一个字节的序列号,该序号前的数据均已被接收。
4位首部长度:TCP 头部的长度,因为 TCP 头部的长度是可变的(20 字节到 60 字节)。
保留字段:这部分目前还没有被使用,通常设置为 0,用于未来可能的协议扩展。
控制位:共有 6 位,分别是 URG、ACK、PSH、RST、SYN 和 FIN:
- URG:当 URG = 1 时,表示紧急指针字段有效,用于发送紧急数据。
- ACK:ACK = 1 时,表示确认号字段有效。
- PSH:PSH = 1 时,接收方在收到数据后应该尽快将数据交给应用程序,而不是等待缓冲区满。
- RST:RST = 1 时,表示重置连接。当出现错误情况,如连接异常中断或者收到无效的数据包时,会发送带有 RST 位的数据包来重置连接。
- SYN:用于建立连接。在 TCP 三次握手过程中,第一次握手时,客户端发送的数据包中 SYN = 1,第二次握手时,服务器返回的数据包中 SYN = 1 且 ACK = 1,第三次握手时,客户端发送的数据包中 ACK = 1。。
- FIN:用于释放连接。当一方完成数据发送,想要关闭连接时,会发送带有 FIN = 1 的数据包。
窗口大小:16 位长。它用于流量控制,指示接收方还能够接收的字节数。
校验和:报文是否在传输过程中出现错误。发送方会计算头部和数据的校验和并填充,接收方会重新计算校验和并与收到的校验和进行比较。如果两者不相等,就表示数据在传输过程中出现了错误,需要进行重传等操作。
紧急指针:当 URG 位被设置为 1 时,紧急指针指向紧急数据的末尾位置。这可以让接收方优先处理紧急数据。
选项:选项字段是可变长度的,用于提供额外的功能,如最大段大小(MSS)协商等。填充字段是为了保证 TCP 头部长度是 32 位的整数倍。
确认应答机制
为了保证消息传输的可靠性,发送方需要知道接收方又没有收到消息,收到了多少字节,为此TCP引入了确认应答机制。
TCP协议中发送的每个字节都有编号即序列号,发送方发送数据时,会在 TCP 段的首部中携带该段数据的起始序列号。即第一个字节的序列号。
接收方收到 TCP 段后,会按序号将它们重新组装成完整的数据流。当接收方接收并处理完一段数据后,会向发送方发送一个确认(ACK)报文段,其中ACK位设为1,同时写入32位确认序号,表示该序列号之前的所有数据都已正确接收。
在以下几种情况下会发送确认报文:
正常接收数据后
-
按序接收:当接收方按顺序正确接收到发送方发送的 TCP 报文段中的数据时,会立即发送确认报文。
-
乱序接收:如果接收方收到的报文段中的数据不是按顺序到达的,接收方会先将其放入接收缓冲区进行排序。当接收方成功将乱序的数据重新排序并确认所有数据都已完整接收后,会发送确认报文,确认序号为期望接收的下一个序列号。
接收方有接收能力时
- 接收窗口更新:接收方的接收窗口大小会随着接收缓冲区的使用情况而动态变化。当接收方的接收窗口大小发生变化,且有更多的空间可以接收数据时,接收方会发送确认报文,在确认报文中告知发送方新的接收窗口大小。
特定事件发生时
- 零窗口探测响应:当发送方收到接收方的零窗口通知后,会启动持续计时器,在计时器到期后发送一个零窗口探测报文段。接收方在收到该探测报文段时,会回复当前的窗口大小,这个回复的报文也是一种确认报文,告知发送方当前的接收窗口状态3。
- 重复确认:如果接收方发现有数据包丢失,会发送重复的确认消息,即连续发送多个相同确认序号的确认报文。当发送方连续收到 3 个或以上的重复 ACK 时,就会立即重传丢失的数据包1。
超时重传机制
对于TCP,只有确认应答还不够,在消息丢失后还要有相应的弥补措施。
当发送方发送一个 TCP 数据包时,会同时启动一个重传定时器。相当于一个定时闹钟,时间是根据往返时间(RTT)估算出来的。
如果定时器超时,发送方还没有收到确认消息,就认为数据包可能丢失了或者确认消息丢失了。此时,发送方会重新发送这个数据包,并重新启动定时器,等待接收方的确认。
对于具体细节可以参考这篇博客:
TCP/IP协议栈:TCP超时重传机制_如果出现二义性直接不作处理,所以直接将rtt的值设置为两倍-CSDN博客
快速重传机制
在 TCP 中,超时重传机制需要等待定时器超时才会重传丢失的数据包。等待时间较长,会影响传输效率。为了提高效率,TCP引入了快速重传机制,可以更快地检测和重传丢失的数据包,减少等待时间,提高 TCP 传输的性能。
接收方在收到数据包时,会发送确认报文,其确认号是期望收到的下一个序列号,即丢失报文的初始序列号。因为在丢失报文之前的数据均被接送。
如果接收方连续收到多个相同确认号的 ACK 报文,就表明某个数据包可能丢失了。接收方会重传数据包。
三次握手
与UDP不同,TCP在进行通信时会先建立连接。这个连接建立的过程被称为 “三次握手”。
第一次握手:
客户端向服务器发送一个设置了 SYN 标志位的 TCP 报文,该报文同时包含客户端随机生成的初始序列号,假设为 x。此时,客户端进入 SYN_SENT 状态,等待服务器的响应。
第二次握手:
服务器接收到客户端的 SYN 报文段后,会向客户端发送一个包含 SYN 和 ACK 标志位的 TCP 报文。SYN 标志位用于同步序列号,服务器也会随机生成一个初始序列号,假设为 y。
ACK 标志位用于确认客户端的连接请求,确认序号为客户端的序列号 x 加 1,即 ack = x + 1。此时,服务器进入 SYN_RCVD 状态。
第三次握手:
客户端接收到服务器的 SYN + ACK 报文段后,会向服务器发送一个包含 ACK 标志位的 TCP 报文段。确认号为服务器的序列号 y 加 1,即 ack = y + 1,而序列号为客户端在第一次握手中发送的序列号 x 加 1,即 seq = x + 1。
服务器收到这个 ACK 报文段后,连接建立成功,双方进入 ESTABLISHED 状态,开始进行数据传输。
四次挥手
四次挥手是 TCP 协议中用于断开连接的过程:
第一次挥手:
客户端调用 close 函数关闭套接字,客户端向服务器发送一个 FIN 标志位被置为 1 的 TCP 报文,该报文包含客户端想要关闭连接的请求,此时客户端进入 FIN_WAIT_1 状态,表示客户端已经没有数据要发送给服务器了,但还可以接收服务器的数据。
第二次挥手:
服务器接收到客户端发送的 FIN 报文后,会发送一个 ACK标志位被置为 1 的 TCP 报文段作为应答,确认序号为收到的 FIN 报文段的序号加 1。服务器进入 CLOSE_WAIT 状态,此时连接处于半关闭状态,即客户端不再发送数据,但服务器还可以继续向客户端发送数据。客户端收到服务器的 ACK 报文段后,进入 FIN_WAIT_2 状态。
第三次挥手:
服务端调用 close 函数关闭套接字,发送 FIN 报文,请求关闭连接,此时服务器进入 LAST_ACK 状态。
第四次挥手:
客户端收到服务器发送的 FIN 报文段后,会发送 ACK 报文段作为应答,确认序号为收到的 FIN 报文段的序号加 1。客户端进入 TIME_WAIT 状态,经过 2MSL(最长报文段寿命——个报文段在网络中可以存在的最长时间)时间后,连接彻底关闭。服务器收到客户端的 ACK 报文段后,立即关闭连接。
为什么第四次挥手后客户端不直接关闭?
确保最后一个 ACK 报文能够到达服务器:客户端发送的最后一个ACK报文有可能丢失。如果服务器没有收到客户端的确认,就会超时重传FIN报文。客户端在TIME_WAIT状态下等待2MSL时间,就可以有足够的时间接收服务器重传的FIN报文,然后重新发送ACK报文,确保服务器能够正常关闭连接。
防止已失效的连接请求报文出现在新连接中:在网络中,可能存在一些延迟的报文段,这些报文段可能是之前连接的残留。客户端在发送完最后一个ACK报文后,等待2MSL时间,就可以使本连接持续的时间内所产生的所有报文段都消失,这样就可以避免下一个新连接中出现旧的连接请求报文,从而防止历史连接中的数据被后面相同四元组(源 IP 地址、源端口号、目的 IP 地址、目的端口号)的连接错误地接收。
发送缓冲区与接收缓冲区
TCP 流量控制是一种确保发送方发送数据的速率与接收方接收和处理数据的能力相匹配的机制。
在 TCP 中数据发送和接收并不是直接发送与接收,而是先拷贝到内核的发送与接收缓冲区中,由内核决定何时发送。
发送数据过程:
应用程序调用发送函数(send()或write())将数据写入内核的发送缓冲区。应用程序在数据拷贝完成后就可以继续执行其他任务,不必等待数据真正被发送出去。
内核会根据当前的网络状况、拥塞窗口大小、接收方的通告窗口,来决定何时将发送缓冲区中的数据发送到网络上。
接收数据过程:
当网络中的数据到达主机时,网卡会将数据接收进来,并传递给内核的接收缓冲区。
应用程序通过调用接收函数(如recv()或read())从内核的接收缓冲区中读取数据。如果接收缓冲区中没有数据,应用程序会阻塞等待,直到有数据可读。
流量控制
如果接收端的接收缓冲区满了,发送端继续发送数据,接收端就会将这些数据丢弃。
TCP 报头中有一个字段为16位窗口大小,这个窗口大小就是表示接收方还有多少缓冲区空间可以用于接收数据。
发送方在发送数据时,会根据接收方的接收窗口大小来控制发送的数据量。接收方在收到数据后,会对数据进行处理,并将剩余的接收缓冲区大小通过 TCP 报文段的窗口字段发送给发送方。发送方根据接收方返回的窗口大小,调整自己的发送窗口大小,从而控制发送数据的速率。
当接收端接收缓冲区满时,发送端得知接收端接收数据的能力为0时会停止发送数据,发送端可以通过两种方法得知什么时候可以发送数据:
- 等待告知:接收端上层将接收缓冲区当中的数据读走后,接收端向发送端发送一个TCP报文,主动将自己的窗口大小告知发送端,发送端得知接收端的接收缓冲区有空间后就可以继续发送数据了。
- 主动询问:发送端每隔一段时间向接收端发送询问报文,该报文不携带有效数据,只是为了询问发送端的窗口大小,直到接收端的接收缓冲区有空间后发送端就可以继续发送数据了
滑动窗口
在数据发送完成后,在没有收到应答之前,我们需要将数据暂存在发送缓冲区,以便于重传,因此在发送缓冲区中,发送缓冲区可以分为三个部分:
那么已发送未应答部分就是滑动窗口, 滑动窗口的大小就是在未接收到应答时,最大可以发送的数据量,实际发送数据时,在实际发送数据时,发送方不需要依次等待每个数据包的确认应答后再发送下一个数据,而是可以在窗口大小的范围内连续发送多个数据帧。
实际上滑动窗口的意义就是提高发送数据的效率 :
滑动窗口的大小限制了发送方在未收到 ACK 之前能够发送的数据量,既保证了数据的连续发送,提高了信道利用率,又避免了发送方发送过多数据导致接收方处理不过来的情况。
滑动窗口的大小为:接收方接收窗口的大小与当前网络拥塞窗口的大小的较小值。
拥塞控制
TCP 拥塞控制是一种确保网络有效运行的机制,通过调节发送方发送数据的速率,避免网络拥塞,以实现高效、可靠的数据传输。拥塞控制算法如下:
慢启动:开始传输时,拥塞窗口的大小初始化为一个最大报文段(MSS)的大小。拥塞窗口为发送方在没有收到接收方确认之前可以发送的数据量。每收到一个确认报文,拥塞窗口大小加倍,呈指数增长,快速增加发送速率,但增长速度逐渐放缓,防止网络拥塞。
拥塞避免: 当拥塞窗口增长到慢启动阈值()后,进入此阶段。此时,发送方每收到一个确认报文,拥塞窗口增加一个较小的固定值,呈线性增长,使发送速率平稳增加,避免网络拥塞。
拥塞检测与处理:当发送方检测到网络拥塞时,会根据不同的情况采取相应的调整措施。
如果是因为收到三个连续的重复确认报文而检测到拥塞,发送方会执行快速重传和快速恢复算法。快速恢复阶段,将慢启动阈值设置为当前拥塞窗口的一半,然后将拥塞窗口设置为慢启动阈值加上三个最大报文段的大小,接着以线性增长的方式增加拥塞窗口,继续发送数据。
如果是因为超时重传定时器超时而检测到拥塞,发送方会将慢启动阈值设置为当前拥塞窗口的一半,将拥塞窗口重置为一个最大报文段的大小,然后重新进入慢启动阶段。
标签:协议,ACK,报文,TCP,发送,详解,接收,客户端 From: https://blog.csdn.net/2301_80926085/article/details/145093162