深入解析TCP:可靠传输的核心机制与实现逻辑

发布于:2025-07-01 ⋅ 阅读:(15) ⋅ 点赞:(0)

Linux 系列



前言

接下来的两篇文章,我将系统讲解TCP协议,涵盖其核心概念与实现逻辑,内容包含TCP协议段格式、确认应答(ACK)机制、超时重传机制、连接管理机制、滑动窗口、流量控制、拥塞控制、延迟应答、捎带应答、面向字节流等具体实现细节。因内容体量较大,分两篇展开介绍 。


一、TCP协议的概念

1.1 TCP协议的特点

下述特点,在后文中都会更详细的介绍

  1. 连接导向性:TCP 是面向连接的运输层协议。应用程序使用 TCP 前,需先建立 TCP 连接;数据传输完成后,要释放已建立的连接 。
  2. 连接特性:每条 TCP 连接仅存在两个端点,且连接模式为点对点(一对一),不支持多对多等复杂拓扑 。
  3. 可靠交付:TCP 提供可靠数据传输服务,经其连接传送的数据,可保障无差错、不丢失、不重复,且严格按序到达
  4. 全双工通信:TCP 支持全双工模式,通信双方的应用进程可随时发送数据。连接两端均设有发送缓存与接收缓存,用于临时存储双向传输的数据 。
  5. 面向字节流:TCP 里的“流”,指的是流入进程或从进程流出的字节序列,以字节为基本处理单元开展数据交互 。

1.2 TCP又叫做传输控制协议

在网络通信建立前,应用程序创建的 TCP 套接字(sockfd)本质上是指向操作系统分配的socket 文件控制块(Socket File Control Block),该控制块内部维护着用于网络数据传输的发送缓冲区和接收缓冲区。当应用层调用 writesend 等发送函数时,实际执行的是将数据从用户空间缓冲区拷贝至内核空间的 TCP 发送缓冲区(即传输层),后续的传输决策(包括发送时机、发送窗口大小、错误处理机制如超时重传等)完全由 TCP 协议栈自主管理,由此TCP又被称为传输控制协议。当应用层调用 readrecv 等接收函数时,数据则是从内核空间的 TCP 接收缓冲区反向拷贝至用户空间缓冲区。
应用层缓冲区,就是我们自己定义的临时存储数据的空间
在这里插入图片描述
当客户端在给服务端发数据时,服务端依然可以给客户端发数据,双方是独立的,所以TCP通信是全双工的。

二、TCP协议段格式

在介绍这部分时,会粗略的介绍TCP的一部分实现机制,重要的部分后面会再次单独介绍,下面我会分点对TCP组成字段一一介绍

在这里插入图片描述

TCP报文携带的有效载荷如何交付给上层

  • 16位源端口:发送方主机进程绑定的端口号
  • 16位目的端口:目的主机进程绑定的端口号

源端口保证发送的请求被接收后,接收主机可以得知该请求的来源。
目的端口保证发送的请求被接收后,该交付给该主机的哪个进程。

TCP报头和报文如何分离

  • 4位首部长度:用于标识 TCP 报文段中数据部分的起始位置距离报文段头部起始处的字节偏移量。

由于选项长度是动态的,TCP实际首部长度不固定,而该字段以4字节为单位,,因此实际首部长度需通过 “字段值 ×4” 计算得出(例如字段值为 5 时,首部长度为 5×4=20 字节),该字段子表示范围为【0000–1111】,所以有效数据长度=报文长度–实际首部长度这一样就可以将二者进行分离。

2.1、TCP的流量控制----------窗口大小(16位)

此处简略介绍
首先我们先以一个极端的例子,感受一下什么是流量控制:

在这里插入图片描述
当客户端频繁向服务端发送请求,而服务端处理能力不足时,若客户端持续高速发送数据,会导致服务端接收缓冲区溢出,造成丢包。为避免这种情况,当服务端接收缓冲区接近满负荷时,客户端就应该降低发送速率或暂停发送。这种协调发送方与接收方数据处理速度的策略,称为流量控制

那么客户端应该慢多少?是如何衡量的呢?或者说流量控制如何实现?

  • 16位窗口大小:表示发送该TCP报文的接受窗口还可以接受多少字节的数据量。该字段用于TCP的流量控制。

在进行网络通讯是,客户端、服务端,都会将自己接收窗口的大小添加进自己的TCP报头中,用来协商收发速度,接收方通过该字段动态通知发送方自己的接收能力,是 TCP 流量控制机制的关键实现方式,说白了这个16位窗口大小就是对方的接收缓冲区还剩多少空间。

在这里插入图片描述

2.2 TCP的确认应答机制

2.2.1 什么是确认应答机制

TCP实现数据可靠传输的基础机制就是确认应答(ACK)机制, 发送方发出数据以后,接收方要给发送方一个回复,确认自己已经收到数据了,这样的回复称为ACK,确认应答报文。

在介绍这块之前,首先我们要先知道为什么网络通信不可靠:在网络通信场景中,长距离数据传输面临的挑战不仅来自中间设备的处理限制,还包括物理链路中信号干扰的影响。当客户端向服务器发送请求时,由于底层网络(如IP协议)采用“尽最大努力交付”机制,请求数据包可能在路由跳转过程中因链路拥塞、硬件故障或电磁干扰导致丢失、损坏或延迟,而客户端无法直接知晓请求是被服务器正常处理,还是在传输途中发生异常。

TCP的确认并应答机制就很好的解决了这里问题: 客户端在向服务端发送数据的时候,每次发送完一个数据,客户端不会马上接着发数据,而是会等待从服务端传来的应答,当我们收到应答后,就可以确定数据成功到达了服务端

在这里插入图片描述
TCP通过肯定的确认应答(ACK)实现可靠的数据传输。当发送端将数据发出之后会等待对端的确认应答。如果有确认应答,说明数据已经成功到达对端。反之,则数据丢失的可能性很大。

这样子可靠性就保证了 ,但是这样子效率太低了。难道我说一句话,你都要先回一句:“我听到了”,然后才说你想回应的话吗?这个效率太低下了,正确的做法应该是将应答和想回复的消息一起发送回去,这种机制我们称为捎带应答
在这里插入图片描述

当然上述方法我们仍面临着许多问题,这就需要其他的一些机制来解决,后面我们会详细介绍。

2.2.2 确认应答机制的优化

在进行网络通信中,我们在考虑可靠性的同时,对效率也是有要求的,从上面部分我们可以看出,当通信一方发送一个请求后,一直在等待对方的应答回复,直至收到对方应答,才进行下一次发送,这也太扯了,所以在实际通信时是以下面的形式进行的:

在这里插入图片描述
这样我们就将串行的应答方式,优化为了并行的方式。

2.3 超时重传机制

在前面部分介绍的确认应答机制,依然存在着数据丢失问题当出现下面情况:
在这里插入图片描述
当主机A向主机B发送了一份数据,而在特定时间内没有收到主机B的应答报文,这时主机A就会认为发送出去的数据丢失了,没有正确到达主机B,主机A就会对这份数据重新补发,这种机制就叫超时重传

基于上述机制,新的问题随之出现:若主机 A 发送的数据未丢失,却在网络中发生阻塞,待主机 A 补发请求并被主机 B 处理后,原数据才抵达主机 B;或者并非主机 A 发送的数据丢失,而是主机 B 回复的应答丢失,促使主机 A 补发数据。无论哪种情形,都会使主机 B 收到重复的请求。为了对上层应用提供可靠的传输,主机 B 显然无法对重复请求逐一处理,这就要求 TCP 报文必须具备去重能力 。

为解决这一问题,需引入一种机制,既能够识别已接收数据,又能判断是否需要接收新数据。实际上,确认应答处理、重发控制以及重复数据控制等功能,均可通过序列号实现:TCP 会为发送数据的每个字节(8 位)按顺序编号,接收端通过解析 TCP 首部中的序列号,结合数据长度,计算出“下一个期望接收的字节序号”,并将该序号作为确认应答(ACK)返回给发送端 。借助序列号与确认应答号的协同作用,TCP 得以实现数据的可靠传输,精准区分新数据与重复数据,避免重复处理,保障通信的有序性与准确性。

在这里插入图片描述
简单而言就是将内核缓冲区视为数组,这样我们的每个数据就天然的具备了自己的编号(数组下标),在发送TCP报文时依据特定算法,一次从缓冲区发送一部分数据,如1~1000,在此TCP报头序号部分,填写1000,当对方主机收到后就会在应答报文中,设置确认序号位1001,在协议中规定确认序号之前的数据已全部收到,即1001之前的数据全部收到,此后客户端主机就可以依据序号来判断,收到的TCP报文是否重复。
在这里插入图片描述

此方法也可以用来处理报文乱序问题:
在这里插入图片描述
比如先发送的报文由于路由原因导致后到达,而后发送的报文先到达等情况,此时就可以依据序号对TCP报文进行调整,其余有点后面介绍。

序号和确认序号

在这里插入图片描述
首先,客户端待发送的数据,会先存入 TCP 的发送缓冲区(内核空间中的缓冲区)。由于 TCP 是面向字节流的协议,该缓冲区可抽象为一个 char 数组,数组里每个存储单元对应一个字节,且自带下标,这意味着缓冲区中每个字节天然具备唯一的顺序编号 。我们写入缓冲区的数据,会严格按照顺序依次存储,后续 TCP 协议正是基于这些字节的固有编号,通过序号机制实现数据的可靠传输 。

含义
序列号用于标识 TCP 报文段中第一个字节的数据序列,在 TCP 连接里,它代表报文段所携数据的起始位置 。借助序列号,TCP 能保障数据传输时的顺序性与完整性,让接收方清晰知晓数据在字节流中的起始点位,为后续有序重组、校验数据奠定基础。

作用
TCP 连接建立阶段,通信双方会各自随机选定初始序列号(ISN) 。后续传输报文段时,每个报文段的序号基于初始值,按所携数据的字节数递增。接收方利用序号,可对乱序抵达的报文段进行重组,确保数据顺序正确、完整。一旦发现接收的报文段不连续,还能通过重传机制,要求发送方补发缺失数据,以此保障可靠传输 。

对于确认序号,其值的含义是:接收方已成功接收确认序号对应数值之前的所有连续报文 。打个比方,若确认序号的值为 1001,意味着接收方不仅收到了序号为 1000 及更早的报文,且这些报文是连续无缺失的。从发送方视角理解,确认序号的值就等同于 自身下一次发送报文时,该报文序号应设置的数值 ,发送方后续可直接从这个序号开始,继续传输新的数据段 。

含义
确认应答号(ACK Number)表示接收方期望接收的下一个报文段的起始序号,其本质是接收方向发送方反馈的“已确认接收数据的边界”——即“我已完整收到该序号之前的所有连续数据,请从这个序号开始发送后续内容”。例如,若确认应答号为1001,则说明序号1000及之前的所有数据已被正确接收,发送方需从1001号字节起继续传输。

作用
确认应答号是TCP实现可靠传输的核心机制,具体功能如下:

  1. 数据完整性校验:接收方解析报文段后,将“当前报文序号+数据长度”作为确认应答号返回,使发送方明确知晓哪些数据已成功抵达。
  2. 重传触发机制:若发送方未在超时周期内收到对应确认应答号,或收到的确认应答号小于预期数据边界,可判定数据丢失或乱序,从而触发重传逻辑。
  3. 有序传输控制:该机制与序列号协同工作,接收方通过确认应答号告知发送方“下一个期望接收的字节位置”,确保发送方按序发送数据,避免因乱序导致的传输错误。
    以实例说明:发送方发送序号501、长度200字节的报文段,接收方正确接收后,会返回确认应答号701(501+200),明确指示“下一个期望接收的字节为701号”。

2.2 TCP协议的六个标志位

介绍这里就不得不提,TCP协议建立连接的过程了
首先我们要明确,服务器在给客户端提供服务时,几乎全部都是处与,一对多的形式:
在这里插入图片描述
在这中形式下,有的客户端发送的TCP报文是给服务器申请建立连接,有的客户端发送的是正在通信的报文,有点发送的是断开连接的报文请求,那么我们的服务器该如何这些不同的请求呢,或者说该如何区分这写不同的报文类型呢?
在TCP协议中的六个标志位,分别代表着不同的请求类型(报文类型)
在这里插入图片描述

以下是TCP协议六个标志位的功能说明表格:

标志位 英文全称 功能描述
URG Urgent 紧急指针有效标识,为1时表示需优先处理紧急数据,配合“紧急指针”字段使用
ACK Acknowledgment 确认号有效标识,为1时确认号字段生效,用于反馈已接收数据的状态
PSH Push 提示接收端应用程序立即从TCP缓冲区读取数据,无需等待缓冲区填满
RST Reset 用于强制重置异常连接,携带该标志的报文为复位报文段,可拒绝非法请求或重建连接
SYN Synchronize 用于发起连接请求,携带该标志的为同步报文段,在三次握手首阶段使用
FIN Finish 通知对方本端要关闭连接

ACK

ACK标志位用于指示报文中的确认号字段是否有效:仅当ACK=1时,确认号字段才具备实际意义。这一机制在TCP的确认回复流程中至关重要——当客户端或服务端发送数据后,接收方需通过应答报文(或捎带应答的报文)反馈接收状态,此时必须将ACK标志位置1。

SYN

在TCP协议中,SYN标志位用于区分客户端的请求类型——当客户端发送的报文段携带SYN=1时,表明这是一个同步报文段,本质是客户端向服务端发起的“连接建立请求”。作为服务端,正是通过检测该标志位来判断客户端意图:若收到SYN=1的报文,便知晓客户端请求建立连接,此时会触发TCP的三次握手流程(客户端发送SYN→服务端回复SYN+ACK→客户端发送ACK),从而在双方之间建立可靠通信通道。
三次握手的具体实现,我会放在下篇文章中介绍

FIN

FIN标志位(Finish)用于标识断开连接请求,当报文段携带FIN=1时,表明发送方已完成数据传输,请求终止TCP连接,该标记位是触发四次挥手断开流程的核心标识。

PSH

首先我们来回顾一下,Client在不断发数据,Server在不断接收数据同时在给Client发送应答,应答报文中包含了16位窗口大小的字段,其实就是在告诉Client自己接收缓冲区剩余空间的大小,以便于Client及时调整自己的发送速度,现在我们要引入一个场景:
当服务端因处理能力不足导致接收缓冲区满溢时,客户端发送的数据会在服务端缓冲区中排队等待处理,进而导致客户端无法及时收到确认应答。若客户端需要实时了解服务端剩余接收空间以调整发送策略,此时发送普通探测报文可能因服务端缓冲区阻塞而无法及时处理。而将探测报文中的PSH标志位置1,可强制要求服务端接收该报文后立即将数据提交给应用层处理,绕过缓冲区排队机制,使客户端能快速获取服务端的窗口状态反馈,从而动态调整发送速率,避免因缓冲区拥塞导致的传输效率下降。

URG

URG标志位(紧急标记位)用于标识数据段中是否包含需优先处理的紧急数据:当URG=1时,表明数据段携带紧急数据,此时后续16位紧急指针字段生效。该机制适用于发送方需让特定数据快速抵达接收方上层的场景——紧急指针表示紧急数据在数据段中的末尾偏移量(即从数据段首字节开始的偏移值),TCP协议规定,紧急数据的长度为“紧急指针值 - 数据段序号 + 1”。当接收方解析到URG=1时,会先读取紧急指针指向的紧急数据(例如,若数据段序号为1000,紧急指针为1005,则紧急数据为1000~1004字节),再处理剩余数据。这类紧急数据被称为“带外数据”,可绕过常规缓冲区排队机制优先交付给应用层,实现高优先级数据的快速传输。

RST
该标志位应该结合三次握手来理解,这里先简单概述

在TCP协议中,RST标志位(复位标记位)用于处理异常连接状态,当通信双方对连接状态的认知出现不一致时,感知到异常的一方会发送携带RST=1的复位报文段,强制终止当前连接并要求重新建立连接。具体场景如下:

  1. 三次握手或四次挥手的异常中断
    若三次握手过程中某一方因网络故障、资源不足等原因无法完成连接建立,或连接建立后某一方(如服务器)因断电、重启等突发情况导致连接状态丢失,此时存活方(如客户端)可能仍持有“连接有效”的状态记录,并继续发送数据。例如服务器重启后已忘记之前的连接,但客户端仍向其发送报文,服务器会解析到异常的连接标识,随即返回RST报文,明确告知“当前连接不存在,需重新发起三次握手”。

  2. 强制终止无效连接
    当接收方收到不属于任何有效连接的报文段(如端口号错误、序列号错位),或检测到连接处于半开状态(一方已关闭连接,另一方仍在发送数据),会通过RST标志位强制复位连接,避免资源浪费。

本质上,RST标志位是TCP处理连接异常的“紧急止损”机制,通过主动告知对方“连接状态异常”,促使双方重新同步状态,确保后续通信基于有效连接进行,避免因状态不一致导致的数据传输错误。

总结

本篇篇文章就介绍到这里,由于TCP协议较为复杂,有很多机制还没有完全介绍,在后面一篇文章中,我会继续对TCP协议的实现细节及各种机制进行补充。


网站公告

今日签到

点亮在社区的每一天
去签到