跳转到内容

TCP

来自轻之舟百科

传输控制协议

传输控制协议
中文名 传输控制协议
英文名 Transmission Control Protocol
缩写 TCP
标准编号 STD 7(RFC 9293)
首次发布 RFC 793(1981年9月)
当前版本 RFC 9293(2022年8月)
端口类型 传输层协议,协议号6
主要功能 面向连接的可靠字节流传输
关键机制 序列号、确认应答、滑动窗口、拥塞控制
设计者 Vint Cerf、Bob Kahn
标准化机构 IETF

传输控制协议(Transmission Control Protocol,缩写TCP) 是TCP/IP协议套件中的核心传输层协议,设计用于在不可靠的IP网络上提供面向连接的、可靠的、有序的字节流传输服务[1]。TCP通过序列号机制和累积确认应答实现对丢失或乱序数据段的检测与重传,利用滑动窗口协议实施流量控制以防止接收方缓冲区溢出,并内置拥塞控制算法以防止发送方速率过快导致网络过载[1]。TCP与上层应用之间通过端口号建立复用/解复用通道,使单台主机上的多个应用程序能够同时维持独立的TCP连接[1]。TCP具有全双工特性——每一个TCP连接支持两条独立的字节流,分别向两个方向传输数据[1]。自1981年首次标准化以来,TCP历经数十年的持续演进,在原始规范基础上增加了多项扩展和改进,是当今互联网中承载Web浏览、电子邮件、文件传输、远程登录等绝大多数应用流量的基础协议[1]。2022年8月发布的RFC 9293收集并整合了自RFC 793以来的所有重要修订,正式取代后者成为TCP的现行标准[1]

历史

传输控制协议的历史可以追溯到1970年代初期。1973年,Robert Kahn和Vint Cerf开始研究一种能够在不同分组交换网络之间互联的通信协议,起初将其称为“传输控制程序(Transmission Control Program)”[2][3]。该方案需要同时解决分组在网络中的路由和数据可靠传输问题。1974年5月,Cerf和Kahn在IEEE Transactions on Communications上发表了题为“A Protocol for Packet Network Intercommunication”的论文,正式提出了现代TCP/IP的核心设计理念[4]。同年12月,Cerf与Carl Sunshine、Yogen Dalal共同发表了RFC 675,记录了早期传输控制程序的完整规范[3]

随着互联网规模的不断扩大,将通信子网的寻址与路由功能从传输功能中分离出来的需求日益迫切。1976年起,研究团队着手将早期的单一体传输控制程序拆分为两个相互独立的协议层:IP负责跨网络的数据包寻址与转发,TCP负责端到端的可靠数据传输[2]。1981年9月,TCP的正式规范RFC 793和IP的正式规范RFC 791同时发布,标志着现代TCP/IP协议套件的标准化完成[3][4]。1983年1月1日,ARPANET从NCP全面切换到TCP/IP,这一天通常被视为现代互联网的正式诞生日期。

RFC 793作为TCP的基础规范沿用了超过四十年。在此期间,IETF陆续发布了数十份RFC文档对RFC 793进行补充和修订,包括TCP拥塞控制的引入(RFC 2581,2000年)、选择性确认机制的提出(RFC 2018,1996年)、显式拥塞通告的引入(RFC 3168,2001年)等重要改进。2022年8月,IETF发布了RFC 9293,将上述所有零散修订整合到一份统一的规范文档中,同时废止了RFC 793以及更新过RFC 793的RFC 879、2873、6093、6429、6528和6691[1]。RFC 9293被归类为互联网标准STD 7,保持了对RFC 793的向后兼容性,并反映了过去数十年间TCP在实际部署中积累的经验与持续改进[1]

核心服务特征

TCP为应用层提供了一系列有别于底层IP的服务特征。

  • 面向连接(Connection-Oriented):在任何数据交换发生之前,通信双方必须通过三报文握手建立一条逻辑连接,并在数据交换完成后通过连接释放过程关闭连接[1]
  • 可靠传输(Reliable Delivery):TCP使用基于累计确认和超时重传的自动重传请求机制,检测并恢复传输中丢失或损坏的数据段,同时利用序列号处理乱序到达的数据包,确保应用层收到的字节流与发送方发出的字节流完全一致且顺序正确[1]
  • 字节流服务(Byte-Stream Service):TCP不维护消息边界的概念,发送端写入的数据被TCP视为一个连续的字节流,由协议自行决定如何将字节流分割成数据段进行传输,接收端的TCP负责将这些数据段重新组装成原始的连续字节流后交付给应用层[5]
  • 流量控制(Flow Control):TCP使用滑动窗口机制使接收方能向发送方通告自己当前可用的接收缓冲区容量,从而防止发送方以超出接收方处理能力的速率发送数据[5]
  • 拥塞控制(Congestion Control):TCP实施多种拥塞控制算法,主动探测网络路径上的可用带宽并据此调整发送速率,防止过多数据注入网络导致中间节点出现严重拥塞和丢包[5]
  • 全双工通信(Full-Duplex Communication):每个TCP连接一经建立,即支持双向数据的同时传输,每条方向上的字节流彼此独立维护各自的序列号和确认号[1]
  • 复用/解复用(Multiplexing/Demultiplexing):TCP利用16位的源端口号和目的端口号,使多台主机上的多个应用程序可以同时维持独立的TCP连接,而互不干扰[1]

工作机制

协议号

在IP协议栈中,TCP被IANA分配了协议号6,该编号出现在IP数据报头部的“协议”字段中,用于标识IP载荷中承载的是TCP报文段而非UDP或其他传输层协议[6]。该协议号在nmap等工具的协议扫描输出中列为tcp 6 TCP[7]

端口号与连接标识

TCP使用16位的端口号对上层应用进行标识。IANA将端口号空间划分为三类:0至1023为系统端口或熟知端口,由IANA统一分配给标准的网络服务(如HTTP使用80端口,HTTPS使用443端口);1024至49151为用户端口或注册端口,可供IANA注册或自由使用;49152至65535为动态端口或私有端口,通常由操作系统在客户端建立连接时临时分配[8]

一个TCP连接由四元组唯一标识:(源IP地址,源端口,目的IP地址,目的端口)。TCP通过该四元组在收发两端正确地将数据段分发到对应的应用进程[1]

序列号与确认应答

TCP为传输字节流中的每一个字节分配一个32位的序列号。发送方的TCP在发送数据段时,会在TCP头部中携带该数据段第一个字节的序列号(Sequence Number)[9]。接收方在收到数据后,回复的ACK报文中携带的确认号(Acknowledgment Number)指示接收方期望收到的下一个字节的序列号,从而隐含确认之前所有字节均已正确接收。这种累积确认机制使TCP能够在不逐个确认每个数据包的情况下高效运行。连接建立阶段,双方各自独立选择一个随机的初始序列号(ISN)作为起始序号[10]

连接建立与释放

TCP连接通过“三报文握手”(Three-Way Handshake)过程建立。具体步骤如下:首先,主动连接发起方(客户端)发送SYN报文段(SYN标志位为1),携带客户端选择的初始序列号ISN_c[10]。服务器收到后,回复SYN+ACK报文段,在确认客户端的序列号(ACK号置为ISN_c+1)的同时,携带有服务器初始序列号ISN_s。客户端收到SYN+ACK报文后,回复ACK报文,确认服务器的序列号(ACK号置为ISN_s+1)[10]。至此连接进入ESTABLISHED状态,双方可以进行数据通信[11]

TCP连接的释放采用“四报文挥手”过程。主动关闭方发送FIN报文段,表示己方已无数据需要发送;对端回复ACK确认该FIN,并继续发送可能尚未发送完毕的数据;当对端也完成数据发送后,发送FIN报文段;最后主动关闭方回复ACK确认该FIN,经过一段时间的等待后完全关闭连接。TCP协议状态机包含十一种状态(LISTEN、SYN-SENT、SYN-RECEIVED、ESTABLISHED、FIN-WAIT-1、FIN-WAIT-2、CLOSE-WAIT、LAST-ACK、CLOSING、TIME-WAIT、CLOSED),系统性地描述了一个TCP端点在整个连接生命周期中的行为,并定义了各状态间的合法迁移路径[1]

数据可靠传输:滑动窗口与流量控制

TCP使用滑动窗口算法提供可靠的、带流量控制的字节流传输服务。滑动窗口协议规定发送方无需等待ACK即可连续发送多个数据段,发送能力上限由两个因子共同决定:一是接收方通过TCP头部中的窗口字段(Window)通告的接收窗口(rwnd),反映了接收方的可用缓冲区容量;二是发送方基于拥塞控制算法自行维护的拥塞窗口(cwnd)[5]。发送方实际能发送的未确认数据量不能超过min(rwnd, cwnd)。当发送方持续收到ACK时,窗口向右滑动,允许后续新数据的发送;当检测到丢包时,窗口收缩并触发重传[5]

差控制与校验和

TCP头部包含一个16位的校验和字段,用于检测TCP报文段(包括TCP头部和有效载荷数据)在传输过程中是否发生损坏。该校验和的计算涉及一个12字节的伪头部,伪头部包含源IP地址、目的IP地址、保留字段(8位0)、协议字段(值为6)以及TCP段长度[12]。伪头部本身并不随数据包在网络上传输,只在发送端和接收端本地临时构造以参与校验和计算。校验和为整个报文段提供差错检测能力,一旦发现损坏,接收方直接丢弃该报文段,发送方的超时重传机制将负责重新发送丢失或损坏的数据[1]

紧急数据机制

TCP头部包含URG标志位和16位的紧急指针字段,用于支持紧急数据机制。当URG位为1时,紧急指针指示从当前序列号开始的偏移量,标明紧急数据结束的位置。该机制允许发送方在正常字节流中插入标记为紧急的数据,使接收方应用程序能够在数据流中优先处理该部分内容。由于此机制在实际应用中导致多种交互与实现层面的复杂性,其使用场景已大幅减少,后续标准化工作中已有文档对该机制的适用性进行了进一步澄清和限制[1]

报文段头部格式

TCP报文段由TCP头部和紧随其后的有效载荷数据组成。TCP头部最小长度为20字节(不含选项),最大长度可根据选项字段的存在而增至60字节[13]。头部长度的具体值由数据偏移字段指示,该字段以32位字为单位计量头部的长度。

TCP头部的字段结构如下:

  • 源端口(Source Port):16位。标识发送端应用进程使用的端口号。
  • 目的端口(Destination Port):16位。标识接收端应用进程使用的端口号。
  • 序列号(Sequence Number):32位。若SYN标志位未置位,该字段为当前报文段数据部分第一个字节的序列号;若SYN标志位置位,该字段为初始序列号(ISN),且实际传输的第一个字节的序列号为ISN+1。
  • 确认号(Acknowledgment Number):32位。若ACK标志位置位,该字段为发送方期望接收的下一个字节的序列号,确认号之前的所有字节均已被正确接收。
  • 数据偏移(Data Offset):4位。以32位字为单位指示TCP头部的总长度,即头部包含多少个4字节字。最小值为5(对应20字节),最大值为15(对应60字节)。
  • 保留字段(Reserved):4位。保留供将来使用,在当前的协议规范中必须填充为0。
  • 标志位(Control Bits):8位(RFC 3168扩展后)。包括如下标志位(自低位至高位):CWR(拥塞窗口已减少)、ECE(ECN-Echo,显式拥塞通告回显)、URG(紧急指针字段有效)、ACK(确认字段有效)、PSH(推送功能)、RST(连接复位)、SYN(同步序列号,用于建立连接)、FIN(发送方不再有数据)。其中PSH标志位在交互式应用场景中提示协议栈立即交付数据,而非等待缓冲区填满;RST标志位用于异常中断一个连接,如接收到非法报文或服务不可达时触发。
  • 窗口(Window):16位。表示从确认号开始算起,接收方愿意接收的数据字节数。该值用于流量控制。
  • 校验和(Checksum):16位。用于计算伪头部、TCP头部和TCP数据三个部分的16位校验和。
  • 紧急指针(Urgent Pointer):16位。若URG标志位置位,该字段指示紧急数据的结束位置与当前序列号之间的偏移量(以字节为单位)。
  • 选项(Options):长度可变,最多40字节。支持多种扩展功能,包括MSS选项、窗口缩放因子选项、时间戳选项、选择性确认(SACK)选项等。扩展选项使用类型-长度-数值格式(TLV)编码。
  • 填充(Padding):在必要时填充附加的0值,确保TCP头部以32位边界结束,并使数据偏移字段与头部实际长度一致。

拥塞控制

TCP拥塞控制机制是协议可扩展性的核心,旨在防止多个TCP连接同时发送数据时因注入网络的数据量超过网络容量而造成严重的丢包和延迟[5]。拥塞控制算法通常在发送端维护拥塞窗口(cwnd),并结合ACK的到达模式来推断网络的拥塞状态。

TCP Tahoe与TCP Reno

TCP Tahoe(以1988年Jacobson在Lawrence Berkeley Laboratory开发的算法为原型)首次引入了现代TCP拥塞控制的核心要素:慢启动和拥塞避免。Tahoe在检测到丢包时(通过超时或收到三次重复ACK)将拥塞窗口重置为1个MSS,重新进入慢启动阶段,并将慢启动阈值(ssthresh)设置为发生丢包时拥塞窗口的一半。TCP Reno在Tahoe的基础上增加了快速恢复机制:当收到三次重复ACK后,TCP Reno不立即将窗口重置为1,而是将拥塞窗口减半(进入拥塞避免阶段),同时将慢启动阈值设置为拥塞窗口的一半,并利用重复ACK维持传输。快速恢复避免了因丢包检测而将拥塞窗口完全重置的低效率问题[14]

TCP CUBIC

CUBIC是Linux、Windows和macOS等主流操作系统中TCP拥塞控制的默认实现。与Reno的线性窗口增长不同,CUBIC使用三次函数来描述窗口随时间的增长曲线,在拥塞窗口接近上一次丢包时的窗口值后进入稳定区域,窗口增长较为平缓,在此稳定区域之外则采用更积极的窗口增长策略。CUBIC的窗口增长函数与RTT无关,使其在高带宽长距离网络以及存在不同RTT的竞争流时具有更好的扩展性和带宽利用率[15]

其他拥塞控制算法变体

在CUBIC之外,业界也发展出了多种旨在优化特定网络场景的TCP拥塞控制变体,包括但不限于:BBR(Google开发的基于瓶颈带宽和RTT的拥塞控制算法)、NewReno(对Reno算法在恢复机制上的改进和细化)、Westwood+(适用于无线网络的拥塞控制算法)以及Compound TCP(由微软开发,在长RTT高带宽环境中引入延迟敏感组件来改进拥塞窗口增长)。

显式拥塞通告

显式拥塞通告是一种支持主动拥塞通知的机制,通过IP头部中的ECN位与TCP头部中的ECE和CWR标志位协同工作。ECN允许路由设备在没有丢包的情况下提前标记拥塞信号,从而使发送端能够在不依赖丢包触发的情况下主动减速。该机制于2001年在RFC 3168中标准化,目前已在主流操作系统的TCP实现中得到广泛支持。

应用与扩展

时间戳选项

时间戳选项在RFC 7323中定义,为TCP报文段提供两个32位时间戳字段(发送时间戳和接收时间戳,分别对应于TSval和TSecr)。PAWS机制使TCP能够区分属于同一连接不同生命周期的新旧报文段,从而在高速长往返时间网络环境中有效避免序列号回绕造成的混乱。同时,时间戳还精确测量RTT,在多个拥塞控制变体中为更准确的RTT估算提供了基础。

选择性确认

SACK通过在TCP选项中携带一个或多个非连续的序列号范围块,使接收方能精确告知发送方哪些数据块已成功到达、哪些数据块出现丢失。在不支持SACK的传统实现中,重传超时后的发送方只能还原到GBN模型,或在新Reno的扩展中恢复有限数据块;SACK使发送方无需盲目重传即可确定丢失边界,只重传真正丢失的段而非整个窗口,显著提升了丢包恢复效率和吞吐量[1]

窗口缩放选项

该选项将TCP窗口的最大大小从基础RFC 793中的65535字节扩展至约1GB。在长时延长距离网络中,标称窗口在未缩放时因BDP较大而限制带宽利用,窗口缩放通过将通告窗口字段与该选项中约定的移位因子结合,使接收方可以在不改动原始协议的前提下大幅提升通告窗口的容量上限。

常见应用

TCP在数据完整性要求严格而时延容忍度相对宽松的场景中占据主导地位,其服务模型掩盖了丢包、乱序、重传和拥塞等底层网络的复杂性。绝大多数现代网络应用依赖TCP作为其传输协议:HTTP/1.x、HTTP/2及HTTP/3尽管QUIC使用了UDP和类似可靠性层,但web传统流量中的大部分仍运行于TCP之上;SMTP及IMAP/POP3邮件传输与收取;FTP数据与命令通道;SSH安全远程登录;Telnet早期远程登录;数据库客户端/服务器远程交互等。

安全

TCP在设计之初优先考虑了数据可靠传输和流量/拥塞控制问题,安全并非首要设计目标。因此,TCP面临多种已知的安全威胁,包括TCP序列号预测攻击(1985年罗伯特·莫里斯最早描述)、会话劫持和连接复位攻击等。由于TCP头部校验和覆盖了IP伪头部部分信息,该校验和可以在一定程度上帮助接收端验证IP地址合法性,但并不提供对加密性的保证。在实际部署中,传输层安全协议(TLS)通常工作在TCP之上,通过在TCP字节流中插入加密/认证握手和加密数据帧,为上层应用提供通信的机密性、数据完整性及端到端身份认证能力。RFC 9293中提及早期TCP校验和依赖于伪头部中的IP源和目标地址进行校验,以维护TCP的端到端属性,但该设计也带来了一些对IP变化的不适应性。现代TCP安全主要依赖上层加密隧道和网络基础设施中的通用安全机制,而非协议本身的内建安全特征。

实现

主流操作系统的内核协议栈中都包含TCP的完整实现。Linux内核的TCP/IP协议栈版本持续演进,长期支持Reno、CUBIC、BBR等多种拥塞控制算法并通过sysctl接口允许用户动态切换;微软Windows中的TCP/IP协议栈从Windows Vista和Windows Server 2008开始引入CTCP等多种改进,自Windows 10及Windows Server 2019起默认启用了基于类似CUBIC的拥塞控制和现代流量/拥塞窗口参数等调优;Apple的macOS和iOS则基于BSD协议栈的XNU内核TCP/IP实现,并同样将CUBIC作为默认拥塞控制算法;除上述完整内核实现外,学术界和嵌入式软件生态中还存在多个简约或形式验证驱动的TCP实现,例如LwIP、μC/TCP-IP以及经过高阶逻辑证明的TCP/HOL4实现等。

参考文献