news 2026/6/6 5:51:59

7、传输层协议 TC

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
7、传输层协议 TC

TCP 协议

TCP 全称为 "传输控制协议(Transmission Control Protocol"). 人如其名, 要对数据的传 输进行一个详细的控制;

TCP 协议段格式

• 源/目的端口号: 表示数据是从哪个进程来, 到哪个进程去;

• 32 位序号/32 位确认号: 后面详细讲;

• 4 位 TCP 报头长度: 表示该 TCP 头部有多少个 32 位 bit(有多少个 4 字节); 所以 TCP 头部最大长度是 15 * 4 = 60

• 6 位标志位:

○ URG: 紧急指针是否有效

○ ACK: 确认号是否有效

○ PSH: 提示接收端应用程序立刻从 TCP 缓冲区把数据读走

○ RST: 对方要求重新建立连接; 我们把携带 RST 标识的称为复位报文段

○ SYN: 请求建立连接; 我们把携带 SYN 标识的称为同步报文段

○ FIN: 通知对方, 本端要关闭了, 我们称携带 FIN标识的为结束报文段

• 16 位窗口大小: 后面再说

• 16 位校验和: 发送端填充, CRC 校验. 接收端校验不通过, 则认为数据有问题. 此 处的检验和不光包含 TCP 首部, 也包含 TCP 数据部分.

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

• 40 字节头部选项: 暂时忽略

TCP 首部格式详解

TCP 首部长度最小为20 字节(没有选项时),最大为60 字节(选项占 40 字节)。下图是每个字段的位置:

text

0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 源端口 | 目的端口 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 序号 (Sequence Number) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 确认序号 (Acknowledgment Number) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 首部长度 | 保留 |U|A|P|R|S|F| 窗口大小 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 校验和 | 紧急指针 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 选项 (可选) | 填充 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 数据 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

1. 源端口(16 位)& 目的端口(16 位)

  • 作用:标识发送方和接收方的应用进程(通过端口号找到对应的 socket)。

  • 细节:端口号加上 IP 首部中的源 IP 和目的 IP,才能唯一确定一个 TCP 连接(四元组)。

  • 常用范围:0~1023 为系统保留(知名端口),1024~49151 为注册端口,49152~65535 为动态/私有端口。


2. 序号(32 位,Sequence Number)

  • 作用:该 TCP 报文段中第一个数据字节的编号

  • 初始序号(ISN):建立连接时双方随机生成(避免历史报文干扰),而非固定从 1 开始。

  • 范围:0 ~ 2^32 - 1,到达最大值后回绕到 0(TCP 通过时间戳或扩展选项处理回绕问题)。

  • 为什么重要:保证数据有序、去重、检测丢失。


3. 确认序号(32 位,Acknowledgment Number)

  • 作用期望收到的下一个字节的序号,同时隐含确认了该序号之前的所有字节都已正确收到。

  • 有效条件:仅当ACK 标志位 = 1时,确认序号字段才有效。

  • 累计确认:Ack = N 表示序号 N-1 及之前的数据都已收到。

  • 示例:收到 Seq=1001 且长度=500 的数据后,回复 Ack=1501(表示期待第 1501 字节)。


4. 首部长度(4 位)

  • 作用:表示 TCP 首部有多少个32 位字(4 字节)

  • 取值范围:5 ~ 15(因为最小 20 字节,即 5×4=20;最大 60 字节,即 15×4=60)。

  • 为什么需要:因为选项字段长度可变,接收方需要知道首部在哪里结束、数据从哪里开始。


5. 保留(6 位)

  • 作用:保留为未来使用,当前必须置 0。


6. 标志位(每个 1 位,共 6 位)

标志名称为 1 时的含义
URGUrgent紧急指针字段有效,报文中有紧急数据(应优先处理)
ACKAcknowledgment确认序号字段有效(除初始 SYN 报文外,几乎所有报文都置 1)
PSHPush提示接收端立即将数据交给应用层,不要等缓冲区满
RSTReset连接出现严重异常,需要强制关闭并重新建立连接(拒绝非法请求)
SYNSynchronize建立连接时使用:SYN=1 表示这是一个连接请求或连接接受报文
FINFinish关闭连接时使用:发送方不再发送数据

补充细节

  • PSH 的实际行为:发送方设置 PSH 后,接收方 TCP 不会等待缓冲区填满,而是立即把数据递交给应用进程(但现代 TCP 实现通常自动优化,很少显式依赖)。

  • RST 常见场景:尝试连接一个未监听的端口、连接超时、收到不属于现存连接的报文。

  • SYN+ACK:服务器回复连接请求时,SYN=1, ACK=1。


7. 窗口大小(16 位)

  • 作用:告诉对方从确认序号开始,自己还能接收多少字节的数据(即接收窗口大小)。

  • 范围:0 ~ 65535 字节。若需要使用更大窗口,可以通过TCP 窗口缩放选项(Window Scale)将窗口值左移若干位(最大可达 1GB)。

  • 用途:实现流量控制,防止发送方发送过快导致接收方缓冲区溢出。

  • 动态变化:接收方根据自身可用缓冲区大小随时调整窗口值并通知发送方。


8. 校验和(16 位)

  • 作用:检测 TCP 首部和数据在传输过程中是否出现比特错误。

  • 计算范围TCP 伪首部(12 字节,包含源 IP、目的 IP、协议号、TCP 长度)+ TCP 首部 + TCP 数据。

    • 伪首部并不真正传输,只在计算校验和时临时构造。

  • 计算方式:将上述所有内容按 16 位字累加,进位回卷,最后取反码。

  • 接收方:同样计算,若结果不为全 1(即 0xFFFF)则丢弃报文。

为什么包含伪首部:为了验证报文是否确实发送给了正确的 IP 和协议(防止 IP 欺骗或路由错误)。


9. 紧急指针(16 位)

  • 作用:仅在URG=1时有效,指向紧急数据的最后一个字节的序号(偏移量,相对于当前序号字段的值)。

  • 用途:发送紧急数据(如中断命令)时,接收方可以立即读取,而不被流控阻塞。

  • 实际使用:现代应用很少依赖,因为带外数据(out-of-band data)在其他机制下可能更复杂。


10. 选项(长度可变,最多 40 字节)

  • 常见选项

    • MSS (Maximum Segment Size):告诉对方自己能接收的最大报文段长度(不包括 TCP 首部)。

    • 窗口缩放因子:用于扩展窗口大小(Windows Scale)。

    • 时间戳:用于计算 RTT 和防止序号回绕(PAWS)。

    • SACK (Selective Acknowledgment):允许接收方告知哪些数据块丢失(提高重传效率)。

  • 填充:确保首部长度是 4 字节的整数倍(用 0 填充)。


总结:各字段的功能分组

功能相关字段
标识进程源端口、目的端口
可靠传输(有序/确认)序号、确认序号、ACK、SYN、FIN
流量控制窗口大小
错误检测校验和
紧急数据URG、紧急指针
连接控制SYN、FIN、RST
提示接收方PSH
扩展功能选项、保留、首部长度

确认应答(ACK)机制

  • 主机A:发送方

  • 主机B:接收方

  • 数据(1~1000):表示该TCP报文段携带的数据字节序号是从 1 到 1000。

  • 确认应答(下一个是1001):主机B收到数据后回复的确认报文,含义是 “我已收到 1~1000 的所有数据,下一个期望收到的字节序号是 1001”。

  • 数据(1001~2000):主机A收到确认后,继续发送下一个数据段,字节序号从 1001 到 2000。

  • 确认应答(下一个是2001):主机B再次回复,表示成功收到 1001~2000,期待序号 2001。

(1)序列号与累计确认
  • TCP 把数据流看作一个字节流,每个字节都有一个唯一的序列号(Seq)。

  • 主机A发送的第一个数据段“1~1000”实际上是指该数据段起始字节序号为 1,长度为 1000 字节。

  • 主机B回复的确认号(Ack)是1001,这是 TCP 的累计确认机制:告诉主机A “我已经收到了序号 1000 及之前的所有字节,请从 1001 开始发送”。

(2)确认应答保证可靠
  • 主机A每发一个数据段,都需要收到来自主机B的确认。

  • 如果一段时间内没有收到确认(超时),主机A会重传未确认的数据。

  • 图中每个数据段都得到了确认,因此主机A可以正常发送下一段。

(3)发送与接收的同步
  • 主机A不会一次性把所有数据全部发出去,而是等待对方确认后再发下一段(这是最简单的停-等协议的体现)。

  • 在实际 TCP 中,为了提高效率,会使用滑动窗口允许连续发送多个数据段再等待确认,但图里展示的是基础逻辑:发送 → 确认 → 再发送。

TCP 将每个字节的数据都进行了编号. 即为序列号.

每一个 ACK 都带有对应的确认序列号, 意思是告诉发送者, 我已经收到了哪些数据; 下 一次你从哪里开始发

超时重传机制

• 主机 A 发送数据给 B 之后, 可能因为网络拥堵等原因, 数据无法到达主机 B;

• 如果主机 A 在一个特定时间间隔内没有收到 B 发来的确认应答, 就会进行重发

但是, 主机 A 未收到 B 发来的确认应答, 也可能是因为 ACK 丢失了;

因此主机 B 会收到很多重复数据. 那么 TCP 协议需要能够识别出那些包是重复的包, 并 且把重复的丢弃掉. 这时候我们可以利用前面提到的序列号, 就可以很容易做到去重的效果.

那么, 如何超时的时间如何确定?

• 最理想的情况下, 找到一个最小的时间, 保证 "确认应答一定能在这个时间内返 回".

• 但是这个时间的长短, 随着网络环境的不同, 是有差异的.

• 如果超时时间设的太长, 会影响整体的重传效率;

• 如果超时时间设的太短, 有可能会频繁发送重复的包

TCP 为了保证无论在任何环境下都能比较高性能的通信, 因此会动态计算这个最大超 时时间

• Linux 中(BSD Unix 和 Windows 也是如此), 超时以 500ms 为一个单位进行控 制, 每次判定超时重发的超时时间都是 500ms 的整数倍.

• 如果重发一次之后, 仍然得不到应答, 等待 2*500ms 后再进行重传.

• 如果仍然得不到应答, 等待 4*500ms 进行重传. 依次类推, 以指数形式递增.

• 累计到一定的重传次数, TCP 认为网络或者对端主机出现异常, 强制关闭连接

连接管理机制

在正常情况下, TCP 要经过三次握手建立连接, 四次挥手断开连接

三次握手(建立连接)

当前状态事件 / 动作下一状态说明
CLOSED服务器执行listen()LISTEN服务器被动监听
CLOSED客户端执行connect()SYN_SENT客户端发送 SYN
LISTEN收到客户端的 SYNSYN_RCVD服务器回复 SYN+ACK
SYN_SENT收到服务器的 SYN+ACKESTABLISHED客户端回复 ACK
SYN_RCVD收到客户端的 ACKESTABLISHED连接建立完成

四次挥手(关闭连接)

关键原则:主动调用close()的一方为主动关闭方,另一方为被动关闭方。下面分别列出两种场景。

场景 A:客户端主动关闭(服务器被动关闭)
角色当前状态事件 / 动作下一状态说明
客户端(主动)ESTABLISHED调用close(),发送 FINFIN_WAIT_1主动发起关闭
服务器(被动)ESTABLISHED收到 FIN,回复 ACKCLOSE_WAIT应用层会收到 EOF
客户端FIN_WAIT_1收到 ACK(对 FIN 的确认)FIN_WAIT_2等待服务器发送 FIN
服务器CLOSE_WAIT应用层处理完数据后调用close(),发送 FINLAST_ACK主动发送 FIN
客户端FIN_WAIT_2收到服务器的 FIN,回复 ACKTIME_WAIT进入 2MSL 等待
服务器LAST_ACK收到客户端对 FIN 的 ACKCLOSED彻底关闭
客户端TIME_WAIT等待 2MSL 后CLOSED防止残留报文干扰
场景 B:服务器主动关闭(客户端被动关闭)
角色当前状态事件 / 动作下一状态说明
服务器(主动)ESTABLISHED调用close(),发送 FINFIN_WAIT_1主动发起关闭
客户端(被动)ESTABLISHED收到 FIN,回复 ACKCLOSE_WAIT应用层会收到 EOF
服务器FIN_WAIT_1收到 ACK(对 FIN 的确认)FIN_WAIT_2等待客户端发送 FIN
客户端CLOSE_WAIT应用层处理完数据后调用close(),发送 FINLAST_ACK主动发送 FIN
服务器FIN_WAIT_2收到客户端的 FIN,回复 ACKTIME_WAIT进入 2MSL 等待
客户端LAST_ACK收到服务器对 FIN 的 ACKCLOSED彻底关闭
服务器TIME_WAIT等待 2MSL 后CLOSED防止残留报文干扰

注意TIME_WAIT只会出现在主动关闭方CLOSE_WAITLAST_ACK出现在被动关闭方。

常见状态解释

状态含义出现位置
LISTEN服务器监听,等待客户端连接服务器
SYN_SENT客户端已发送 SYN,等待 SYN+ACK客户端
SYN_RCVD服务器收到 SYN,已回复 SYN+ACK,等待 ACK服务器
ESTABLISHED连接已建立,可以传输数据双方
FIN_WAIT_1主动关闭方已发送 FIN,等待 ACK主动方
FIN_WAIT_2主动关闭方已收到 FIN 的 ACK,等待对方 FIN主动方
CLOSE_WAIT被动关闭方收到 FIN,等待应用层关闭被动方
LAST_ACK被动关闭方已发送 FIN,等待最终 ACK被动方
TIME_WAIT主动关闭方收到 FIN 并回复 ACK,等待 2MSL主动方
CLOSED连接完全关闭双方

补充:

  1. TIME_WAIT为什么要等 2MSL?

    • 保证主动关闭方发送的最后一个 ACK 能到达对方(若丢失,对方重发 FIN,自己还能响应)。

    • 让本次连接的所有残留报文在网络中消失,避免干扰新连接。

  2. CLOSE_WAIT容易出问题

    • 如果被动关闭方的应用层没有及时调用close(),连接会一直卡在CLOSE_WAIT,导致文件描述符泄漏。

详细解释:

一、前期准备(服务器端先启动)

1. 服务器端应用层
  • listenfd = socket():创建一个监听 socket,返回文件描述符listenfd

  • bind(listenfd, 服务器地址端口):将listenfd绑定到服务器的 IP 和端口(例如0.0.0.0:8080)。

  • listen(listenfd, 连接队列长度):将listenfd变为被动监听状态,内核为该 socket 维护一个已完成连接队列(backlog)。

2. 服务器端 TCP 层状态
  • 执行listen()后,服务器 TCP 状态从CLOSEDLISTEN,等待客户端连接。

此时服务器阻塞在accept()调用上,等待客户端连接到来。


二、TCP 三次握手(建立连接)

1. 客户端应用层
  • fd = socket():创建主动 socket。

  • connect(fd, 服务器地址端口):发起连接请求,阻塞等待服务器应答。

2. 客户端 TCP 层状态
  • 调用connect()后,客户端状态:CLOSEDSYN_SENT(发送 SYN 报文)。

3. 服务器端 TCP 层
  • 收到 SYN 后,状态:LISTENSYN_RCVD,并回复 SYN+ACK。

  • 客户端收到 SYN+ACK 后,状态:SYN_SENTESTABLISHED,并回复 ACK。

  • 服务器收到 ACK 后,状态:SYN_RCVDESTABLISHED

4. 应用层返回
  • 客户端connect()返回,表示连接建立成功。

  • 服务器端阻塞的accept()返回,生成一个新的已连接 socketconnfd,用于与该客户端通信。

注:accept()返回后,服务器 TCP 层已经处于ESTABLISHED状态。


三、数据传输(可循环多次)

服务器端应用层:
  1. read(connfd, buf, size):阻塞等待客户端请求数据。

  2. 收到数据后read返回,处理请求

  3. write(connfd, buf, size):向客户端发送应答数据。

  4. 继续循环read→ 处理 →write,形成多次请求-应答(图中所示“循环多次”)。

客户端应用层:
  • 图中未画客户端的数据发送,但通常客户端也会write发送请求,read接收应答。

TCP 层状态:
  • 整个数据传输期间,双方 TCP 状态保持在ESTABLISHED

  • 每次write产生数据报文,收到ACK确认;每次read获取对方发来的数据。

图中客户端 TCP 层状态一栏写着DATAACK,这并非正式状态,而是表示数据发送和确认阶段。


四、TCP 四次挥手(关闭连接)

以服务器端主动关闭为例(服务器调用close(connfd))。

1. 服务器端应用层调用close(connfd)
  • TCP 层发送 FIN 报文,主动关闭

2. 服务器端 TCP 状态转移
  • ESTABLISHEDFIN_WAIT_1(发送 FIN 后)。

  • 收到客户端对 FIN 的 ACK 后:FIN_WAIT_1FIN_WAIT_2

  • 收到客户端的 FIN 后:发送 ACK,FIN_WAIT_2TIME_WAIT(等待 2MSL 后关闭)。

  • TIME_WAITCLOSED

3. 客户端 TCP 状态转移(被动关闭)
  • 收到 FIN 后:发送 ACK,ESTABLISHEDCLOSE_WAIT(图中未显示,但标准是CLOSE_WAIT)。

  • 客户端应用层调用close()后:发送 FIN,状态CLOSE_WAITLAST_ACK

  • 收到服务器对 FIN 的 ACK 后:LAST_ACKCLOSED

图中客户端 TCP 层状态只画到了FIN_WAIT_2?实际上对客户端来说,被动关闭时没有FIN_WAIT_1/2,只有CLOSE_WAITLAST_ACK。图中可能简化了,或者画的是客户端主动关闭的情况。建议按标准理解。


五、“循环多次”的含义

  • 服务器端:在accept()得到connfd后,在一个循环中反复read/write,处理同一条连接上的多次请求(例如 HTTP 持久连接)。

  • 外层循环accept()本身可以循环,接受多个客户端的连接,每个连接分配一个connfd,分别处理。

在服务器端标注了两个“循环多次”:

  • 内层:对同一个connfd反复读请求 → 发应答。

  • 外层:不断accept()新连接。


六、关键总结

系统调用作用对应 TCP 状态变化
socket()创建套接字不改变状态
bind()绑定地址端口无状态变化
listen()变为监听套接字CLOSEDLISTEN
accept()接受连接返回已连接套接字,状态不变
connect()主动连接CLOSEDSYN_SENTESTABLISHED
read()/write()读写数据保持ESTABLISHED
close()关闭连接触发四次挥手,状态变化如上

TCP 状态转换的汇总

• 较粗的虚线表示服务端的状态变化情况;

• 较粗的实线表示客户端的状态变化情况;

• CLOSED 是一个假想的起始点, 不是真实状态;

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/6 5:51:06

m3u8d终极指南:如何快速下载加密m3u8视频并自动转MP4

m3u8d终极指南:如何快速下载加密m3u8视频并自动转MP4 【免费下载链接】m3u8d m3u8视频下载工具, 提供windows/macos图形界面, 下载后自动将ts文件合并、转换格式为mp4 项目地址: https://gitcode.com/gh_mirrors/m3/m3u8d m3u8d是一款功能强大的m3u8视频下载…

作者头像 李华
网站建设 2026/6/6 5:45:01

超越手动调参:利用STorM32的Scripts功能实现自动化巡检与延时摄影

超越手动调参:利用STorM32的Scripts功能实现自动化巡检与延时摄影 当三轴云台完成基础PID调参后,它就像一位训练有素的舞者,能够精准保持姿态稳定。但对于追求更高阶应用的开发者来说,这种"静态平衡"只是起点。STorM32控…

作者头像 李华
网站建设 2026/6/6 5:44:08

让机器学习模型在真实世界中“活下来”的生存法则

1. 为什么“模型上线”不是终点,而是系统性风险的起点?你有没有经历过这样的场景:凌晨两点,手机突然疯狂震动——生产环境的告警群炸了。核心风控模型的延迟从平均12ms飙到850ms,支付链路开始排队,客服电话…

作者头像 李华