网络运输层之(1)TCP协议基础
Author: Once Day Date: 2024年9月12日
一位热衷于Linux学习和开发的菜鸟,试图谱写一场冒险之旅,也许终点只是一场白日梦…
漫漫长路,有人对你微笑过嘛…
全系列文章可参考专栏: 通信网络技术_Once-Day的博客-CSDN博客。
参考文章:
- 《TCP/IP详解卷一》
- TCP协议详解 (史上最全)-CSDN博客
- TCP协议详解 - 知乎 (zhihu.com)
- 计算机网络:这是一份非常全面&详细的TCP/IP协议学习指南-腾讯云开发者社区-腾讯云 (tencent.com)
- 计算机网络原理梳理丨清晰认识 TCP/IP 协议-腾讯云开发者社区-腾讯云 (tencent.com)
文章目录
- 网络运输层之(1)TCP协议基础
- 1. 概述
- 1.1 介绍
- 1.2 服务模型
- 1.3 RFC文档
- 2. 报文协议
- 2.1 TCP报文格式
- 2.2 TCP校验和
- 2.2 三次握手
- 2.3 四次挥手
- 2.4 自动重传
- 2.5 流量控制(滑动窗口)
- 2.6 拥塞控制
1. 概述
1.1 介绍
传输控制协议(Transmission Control Protocol,TCP)是一种面向连接的、可靠的、基于字节流的传输层通信协议。它是当今互联网中最广泛使用的传输协议之一,为各种网络应用程序提供了可靠的数据传输服务。
TCP协议在传输数据时,会将数据分成一个个的报文段(segment)进行传输。每个报文段都包含了源端口号、目的端口号、序列号、确认号、控制位等重要信息,以确保数据传输的可靠性和有序性。
TCP协议的发展历程可以追溯到20世纪70年代末,经过几十年的演变和完善,已经成为当今互联网中最重要的传输层协议之一。TCP协议的发展大致经历了以下几个阶段:
- 初始规范阶段(20世纪80年代):TCP协议的原始规范RFC 793发布,奠定了TCP的基本功能和特性,如面向连接、可靠传输和全双工通信等。随后,RFC 1122对TCP规范进行了修订和完善。
- 性能优化阶段(20世纪90年代):为了适应互联网的快速发展,TCP引入了多项性能优化措施,如RFC 1323中的窗口缩放、时间戳和PAWS算法,以及RFC 2018中的选择性确认(SACK)机制,用于提高TCP在高速、长距离网络中的性能和可靠性。
- 拥塞控制阶段(20世纪90年代末至21世纪初):TCP拥塞控制算法的不断完善和成熟,从RFC 2581到RFC 5681,奠定了现代TCP拥塞控制的基础。同时,RFC 3168引入了显式拥塞通知(ECN)机制,允许网络向TCP反馈拥塞信息。
- 高性能扩展阶段(21世纪10年代):为了进一步提高TCP在高速、长距离网络中的性能,RFC 7323对TCP的高性能扩展进行了更新,包括窗口缩放、时间戳和PAWS算法等。
- 现代TCP规范阶段(21世纪10年代至今):RFC 8312作为当前最新的TCP规范文档,对TCP的各个方面进行了全面的描述和规范,是当前TCP协议的权威参考。
1.2 服务模型
TCP协议的主要特点如下:
-
面向连接:在数据传输之前,TCP通信的双方必须先建立连接,确保双方都准备好进行数据交换。
-
可靠性:TCP使用序列号、确认应答、重传等机制来确保数据的可靠传输,保证数据不会丢失、重复或乱序。
-
字节流:TCP将应用程序传输的数据视为一连串的字节流,不关心字节流的具体含义,只负责把数据从一端传送到另一端。
-
全双工:TCP支持全双工通信,即数据可以同时在两个方向上传输,双方都可以同时发送和接收数据。
-
流量控制:TCP通过滑动窗口机制实现流量控制,防止发送方发送数据的速度超过接收方接收数据的速度,避免网络拥塞。
-
拥塞控制:TCP采用拥塞控制算法,如慢启动、拥塞避免、快速重传和快速恢复等,来适应网络拥塞状况,调整发送速率,提高网络利用率。
1.3 RFC文档
下面是TCP相关的RFC文档:
-
RFC 793 - Transmission Control Protocol (1981),TCP协议的原始规范,定义了TCP的基本功能和报文格式。
-
RFC 1122 - Requirements for Internet Hosts - Communication Layers (1989),对TCP的规范进行了修订和完善,提出了许多新的要求和建议。
-
RFC 1323 - TCP Extensions for High Performance (1992),引入了窗口缩放、时间戳和PAWS算法,用于提高TCP在高速、长距离网络中的性能。
-
RFC 2018 - TCP Selective Acknowledgment Options (1996),定义了TCP选择性确认(SACK)选项,用于改进TCP的丢包恢复能力。
-
RFC 2581 - TCP Congestion Control (1999),对TCP拥塞控制算法进行了详细描述,包括慢启动、拥塞避免、快速重传和快速恢复等算法。
-
RFC 2883 - An Extension to the Selective Acknowledgement (SACK) Option for TCP (2000),引入了D-SACK(Duplicate SACK),用于检测网络中的数据包重复现象。
-
RFC 3168 - The Addition of Explicit Congestion Notification (ECN) to IP (2001),定义了显式拥塞通知(ECN)机制,允许路由器向TCP发送方反馈网络拥塞信息。
-
RFC 3390 - Increasing TCP’s Initial Window (2002),提出了增加TCP初始窗口大小的建议,以提高TCP在短流量传输中的性能。
-
RFC 3782 - The NewReno Modification to TCP’s Fast Recovery Algorithm (2004),对TCP快速恢复算法进行了修改,提出了NewReno算法,改进了TCP的丢包恢复性能。
-
RFC 4138 - Forward RTO-Recovery (F-RTO): An Algorithm for Detecting Spurious Retransmission Timeouts with TCP and the Stream Control Transmission Protocol (SCTP) (2005),提出了F-RTO算法,用于检测和处理TCP中的虚假超时重传问题。
-
RFC 5681 - TCP Congestion Control (2009),对TCP拥塞控制算法进行了修订和完善,融合了之前多个RFC文档中的内容。
-
RFC 6298 - Computing TCP’s Retransmission Timer (2011),介绍了计算TCP重传计时器的算法和方法。
-
RFC 6582 - The NewReno Modification to TCP’s Fast Recovery Algorithm (2012),对RFC 3782中的NewReno算法进行了更新和完善。
-
RFC 7323 - TCP Extensions for High Performance (2014),对TCP的高性能扩展进行了更新,包括窗口缩放、时间戳和PAWS算法等。
-
RFC 7413 - TCP Fast Open (2014),介绍了TCP快速打开(TFO)机制,用于减少TCP连接建立的延迟。
-
RFC 8312 - CUBIC for Fast Long-Distance Networks (2018),介绍了CUBIC拥塞控制算法,适用于高速、长距离网络。
2. 报文协议
2.1 TCP报文格式
TCP报文(也称为TCP段,segment)是TCP协议通信过程中传输的数据单元,每个TCP报文都由报文头部和数据部分组成。
下面是各个字段的含义:
-
源端口(Source Port,16位):表示发送TCP报文的源端口号。
-
目的端口(Destination Port,16位):表示接收TCP报文的目的端口号。
-
序列号(Sequence Number,32位):表示当前报文段中第一个字节的序号。TCP给每个字节都赋予了一个序列号,这是一个32位的无符号数字,到达 2 32 − 1 2^{32}-1 232−1后再循环到0,每个被交换的字节都已编号。
-
确认号(Acknowledgment Number,32位):表示期望接收的下一个字节的序号,也就是当前已成功接收的字节序号加1。
-
数据偏移(Data Offset,4位):表示TCP报文头部的长度,单位为4字节。
-
保留位(Reserved,4位):保留字段,供将来使用。
-
控制位(Control Bits,8位):包括CWR,ECE,URG、ACK、PSH、RST、SYN和FIN。
-
CWR:拥塞窗口减少,用于发送方降低它的发送速率。
-
ECE:ECN回显,发送方接收到了一个更早的拥塞通告。
-
URG:紧急指针(Urgent Pointer),较少使用。
-
ACK:确认号(Acknowledgment Number)字段有效,连接建立之后一般都默认启用,也就是除了初始和末尾报文段之外的所有报文。
-
PSH:接收方应尽快将数据传递给应用程序。
-
RST:重置连接,经常因为错误取消连接。
-
SYN:同步序号,用于初始化连接。
-
FIN:发送方已经完成数据发送。
-
-
窗口大小(Window Size,16位):表示接收方当前可接收的字节数,用于流量控制。这个字段最大值是65535,可以通过窗口缩放选项(Window Scale)对其进行缩放,从而提供更高的上限值。
-
校验和(Checksum,16位):用于检验TCP报文头部和数据部分的完整性。
-
紧急指针(Urgent Pointer,16位):当URG标志位置1时有效,指示紧急数据的末尾在报文段中的位置。
-
选项(Options,可变长度):TCP头部的可选字段,用于实现一些特殊功能,如最大报文段长度(MSS)、窗口缩放因子、时间戳等。
-
填充(Padding,可变长度):用于确保TCP头部长度为4字节的整数倍。
2.2 TCP校验和
TCP校验和是TCP报文头部中的一个重要字段,用于验证TCP报文在传输过程中是否出现了误码或损坏。
TCP伪头部是计算校验和时使用的一个虚拟头部,它包含了一些来自IP头部的信息。伪头部的格式如下:
校验和的计算方式如下(与IP、ICMP和UDP协议类似):
- 将TCP伪头部、TCP头部和数据部分看作一个连续的字节流。
- 将字节流划分为16位(2字节)的字。
- 如果字节流的长度为奇数,在末尾添加一个全零字节,使字节流长度变为偶数。
- 将所有16位字相加,得到一个32位的和。
- 将32位的和的高16位与低16位相加,得到一个16位的和。
- 将16位的和取反,得到TCP校验和的值。
接收方在收到TCP报文后,会按照相同的方法计算校验和,并与报文中的校验和字段进行比较。如果两者相同,说明报文在传输过程中没有出现差错;如果不同,则说明报文在传输过程中出现了差错,需要进行重传或错误处理。
但这种校验和对于超大量数据来说,仍然是不够健壮,应用层仍然需要采取自定义的手段来保证应用层数据可靠性。
2.2 三次握手
TCP是一种面向连接的可靠传输协议,在通信双方进行数据传输之前,需要先建立连接。TCP使用三次握手(Three-Way Handshake)的方式来建立连接,下面是示意图:
(1) 第一次握手(SYN),客户端向服务器发送一个SYN(同步)报文:
- 设置SYN标志位为1,表示这是一个连接请求报文。
- 随机生成一个初始序列号(ISN,Initial Sequence Number),例如ISN=X。
- 可选地携带其他参数,如最大报文段长度(MSS)等。
(2) 第二次握手(SYN+ACK),服务器收到客户端的SYN报文后,如果同意建立连接,则返回一个SYN+ACK报文:
- 设置SYN标志位为1,ACK标志位为1,表示这是一个连接接受报文。
- 服务器也随机生成一个初始序列号,例如ISN=Y。
- 确认号(Acknowledgment Number)设置为客户端的ISN加1,即Ack=X+1。
- 可选地携带其他参数。
(3) 第三次握手(ACK),客户端收到服务器的SYN+ACK报文后,向服务器发送一个ACK报文:
- 设置ACK标志位为1,表示这是一个确认报文。
- 序列号(Sequence Number)设置为客户端的ISN加1,即Seq=X+1。
- 确认号设置为服务器的ISN加1,即Ack=Y+1。
- 可选地携带其他参数或数据。
2.3 四次挥手
当客户端或服务器任一方需要关闭TCP连接时,就会启动连接释放的过程。TCP使用四次挥手(Four-Way Handshake)的方式来释放连接,下面是示意图:
(1) 第一次挥手(FIN),假设客户端先发起连接释放,客户端向服务器发送一个FIN(终止)报文:
- 设置FIN标志位为1,表示这是一个连接释放请求报文。
- 序列号(Sequence Number)设置为当前的序列号,例如
Seq=X
。
(2) 第二次挥手(ACK),服务器收到客户端的FIN报文后,向客户端发送一个ACK报文:
- 设置ACK标志位为1,表示这是一个确认报文。
- 确认号(Acknowledgment Number)设置为客户端的序列号加1,即
Ack=X+1
。
(3) 第三次挥手(FIN),服务器完成数据发送后,也向客户端发送一个FIN报文:
- 设置FIN标志位为1,表示这是一个连接释放请求报文。
- 序列号设置为当前的序列号,例如
Seq=Y
。
(4) 第四次挥手(ACK),客户端收到服务器的FIN报文后,向服务器发送一个ACK报文:
- 设置ACK标志位为1,表示这是一个确认报文。
- 确认号设置为服务器的序列号加1,即
Ack=Y+1
。
注意,客户端在进入CLOSED状态之前,需要经过TIME_WAIT状态,并等待2MSL的时间。这样做的目的是确保网络中所有的报文都已经被接收或丢弃,防止新连接误接收旧连接的报文。
2.4 自动重传
在数据通信中,由于各种原因(如信道噪声、网络拥塞等),数据报文在传输过程中可能会出现丢失、损坏或重复等问题。为了确保数据的可靠传输,通信双方通常使用自动重复请求(Automatic Repeat reQuest,ARQ)机制和自动重传功能。
自动重复请求是一种在通信双方之间实现可靠数据传输的方法,它要求接收方在收到数据后向发送方发送确认(ACK),如果发送方在一定时间内未收到确认,则认为数据丢失并重新发送。ARQ主要有以下三种方式:
- 停止等待ARQ(Stop-and-Wait ARQ):发送方每发送一个数据包就停止发送,等待接收方的确认,收到确认后再发送下一个数据包。
- 回退N帧ARQ(Go-Back-N ARQ):发送方可以连续发送多个数据包,如果接收方发现有数据包丢失,则要求发送方重传丢失的数据包及其后的所有数据包。
- 选择重传ARQ(Selective Repeat ARQ):发送方可以连续发送多个数据包,如果接收方发现有数据包丢失,则只要求发送方重传丢失的数据包,而不影响其他正确接收的数据包。
TCP采用了一种基于选择重传ARQ的自动重传机制,以确保数据的可靠传输:
- 超时重传(Timeout Retransmission):当发送方发送了一个数据包后,会启动一个计时器。如果在计时器超时之前没有收到接收方的确认,发送方就会重新发送这个数据包。
- 快速重传(Fast Retransmission):当接收方收到一个失序的数据包时,会立即发送一个重复的ACK(即使还没有收到期望的数据包)。当发送方收到三个或更多个重复的ACK时,会立即重传对应的数据包,而不等待计时器超时。
- 选择确认(Selective Acknowledgment,SACK):SACK是TCP的一个可选扩展,它允许接收方在ACK中指明已经成功接收的数据包的范围,这样发送方就可以只重传丢失的数据包,提高了重传的效率。
- 重传超时时间(Retransmission Timeout,RTO)的计算:TCP根据网络的往返时间(Round-Trip Time,RTT)和RTT的变化情况,动态地计算重传超时时间,以适应网络状况的变化。
2.5 流量控制(滑动窗口)
在TCP通信中,滑动窗口(Sliding Window)是一种用于实现流量控制的机制。它允许发送方根据接收方的接收能力动态调整发送数据的速率,以避免接收方的缓冲区溢出或网络拥塞。
滑动窗口是指在任意时刻,发送方可以发送的数据范围。这个范围由两个指针界定:发送窗口的左边界和右边界。左边界表示已经发送并得到确认的数据的最大序号,右边界表示可以发送的数据的最大序号。
窗口的大小由接收方通告的窗口大小(rwnd,Receiver Window)决定。发送方的发送窗口不能超过rwnd,以防止发送过多的数据导致接收方的缓冲区溢出。
随着数据的发送和确认,滑动窗口会不断向右移动,允许发送方发送新的数据。这就是"滑动窗口"的由来。
TCP使用滑动窗口实现了流量控制,具体过程如下:
-
接收方在ACK报文中通告自己的接收窗口大小(rwnd),表示自己当前可以接收的数据量。
-
发送方根据接收方通告的rwnd和自己的拥塞窗口(cwnd,Congestion Window)计算发送窗口的大小,取两者的最小值:
send_window = min(rwnd, cwnd)
-
发送方只能在发送窗口允许的范围内发送数据,即已发送但未确认的数据量不能超过发送窗口的大小。
-
当接收方处理了一部分数据后,其接收缓冲区空出了空间,就会通过ACK报文通告更大的rwnd,允许发送方发送更多的数据。
-
如果接收方的接收缓冲区满了,会通告一个零的rwnd,发送方就必须停止发送数据,直到接收方再次通告非零的rwnd。
TCP的滑动窗口机制可以动态调整发送速率,使其与接收方的接收能力相匹配,从而实现了流量控制。
2.6 拥塞控制
除了流量控制,TCP还具有拥塞控制(Congestion Control)的功能,用于防止网络拥塞和崩溃。拥塞控制允许TCP在网络拥塞时调整发送速率,以避免进一步加剧拥塞,并在网络恢复后逐步增加发送速率。
TCP使用拥塞窗口(Congestion Window,cwnd)来控制发送速率。拥塞窗口表示在任意时刻,发送方可以发送的未确认数据的最大量。与接收方通告的接收窗口(rwnd)不同,拥塞窗口是发送方根据网络拥塞状况自行调整的。
发送窗口的大小由拥塞窗口和接收窗口共同决定:
send_window = min(cwnd, rwnd)
TCP采用了慢启动(Slow Start)和拥塞避免(Congestion Avoidance)两种算法来调整拥塞窗口的大小:
-
慢启动:当连接建立时,cwnd初始化为一个小值(通常为1个MSS,最大段大小)。每收到一个ACK,cwnd就增加1个MSS,这导致cwnd以指数方式增长。当cwnd达到慢启动阈值(ssthresh)时,进入拥塞避免阶段。
-
拥塞避免:在拥塞避免阶段,每收到一个ACK,cwnd增加1/cwnd个MSS。这导致cwnd以线性方式缓慢增长,直到出现拥塞事件(如超时或收到重复ACK)。
-
快速重传和快速恢复:当收到三个或更多重复ACK时,TCP执行快速重传,立即重传丢失的数据包。同时,执行快速恢复,将ssthresh设置为当前cwnd的一半,并将cwnd设置为ssthresh加上3个MSS,然后进入拥塞避免阶段。
-
超时:如果发生超时,TCP将ssthresh设置为当前cwnd的一半,将cwnd重置为1个MSS,然后重新进入慢启动阶段。
通过这些算法,TCP可以在网络拥塞时迅速降低发送速率,在网络恢复后逐步提高发送速率,从而实现了拥塞控制。
除了上述基本的拥塞控制算法,TCP还有一些其他的拥塞控制算法,如:
-
TCP Tahoe:上述基本算法的原始版本。
-
TCP Reno:在快速恢复后,如果收到部分ACK,则退出快速恢复并进入拥塞避免阶段。
-
TCP NewReno:改进了快速恢复算法,可以处理多个数据包丢失的情况。
-
TCP Vegas:基于延迟而不是丢包来检测拥塞,试图在队列积累之前就降低发送速率。
-
TCP CUBIC:目前在Linux系统中使用的默认拥塞控制算法,使用立方函数来调整cwnd,适用于高带宽、高延迟的网络。
Once Day
也信美人终作土,不堪幽梦太匆匆......
如果这篇文章为您带来了帮助或启发,不妨点个赞👍和关注,再加上一个小小的收藏⭐!
(。◕‿◕。)感谢您的阅读与支持~~~