TCP连接管理与可靠传输:三次握手、四次挥手与状态机详解
2026/9/17 6:54:20 网站建设 项目流程

简介:这是一份聚焦网络面试高频考点的计算机基础PDF总结,适合正在准备校招/社招的软件工程师、网络运维人员以及需要系统梳理TCP/IP知识体系的学习者。资源共1个PDF文件,压缩包整体仅2.08MB,内容按网络模型、TCP/IP协议族、传输层协议、网络层协议的顺序编排,目录结构清晰,便于按主题快速定位。目前已有969人学习下载,内部覆盖OSI七层模型与TCP/IP四层模型的对比、TCP三次握手与四次挥手、TCP状态机、TIME_WAIT、超时重传与快速重传、流量控制、拥塞控制、可靠传输与滑动窗口、TCP报文头字段解析,以及IPv4/IPv6、ICMP、ARP、IGMP等网络层协议说明;同时给出TCP与UDP、SCTP的差异对比。该资料从模型到协议,再从协议到具体机制,形成了完整的复习闭环,适合快速建立知识框架,进行考前突击或日常巩固。

1. 为什么计算机网络基础能决定面试和排障的下限

计算机网络基础是后端开发、运维、嵌入式乃至客户端工程师都绕不开的底层能力。面试中,三次握手、四次挥手、TIME_WAIT 这些点被反复追问,但很多人停留在“背结论”的层面,一旦让用命令验证或解释为什么这样设计,就卡住了。实际排查中,连接超时、端口耗尽、重传频繁,根因往往就藏在 OSI 分层和 TCP 状态机里。这篇文章把常见面试问题拆成可动手复现的实验:用 tcpdump 看握手包、用 ss 观察状态跳转、用 ping 估算 RTT,再结合 ARQ 和窗口机制讲透可靠传输。适合正在准备面试的人,也适合想真正读懂 TCP 连接状态、不再靠重启服务解决问题的工程师。

2. 从OSI七层到TCP/IP四层:分层模型、差异与抓包验证

2.1 OSI七层模型:理论框架的职责划分

OSI 七层模型把网络通信拆成物理层、数据链路层、网络层、传输层、会话层、表示层和应用层。每层的职责要拎清楚:物理层处理比特流的传输,负责数模、模数转换;数据链路层在直接相连的节点间传输数据帧,做差错检测和纠正,并定义 MAC 地址;网络层负责跨节点路由,用 IP 地址寻址;传输层提供端到端的可靠传输,负责分片重组、差错恢复和流量控制;会话层管理应用间的会话,提供同步与恢复;表示层处理数据格式、加密和压缩;应用层承载文件传输、邮件、远程登录等具体协议。

面试中常问的就是“为什么需要分这么多层”。从工程角度看,分层让每层只关心自己的协议,上层不用管下层物理细节,下层也不用管上层业务语义。比如 HTTP 应用层只管请求响应,TCP 传输层负责保证字节流有序到达,IP 网络层只做路由转发。这种解耦让协议栈可以独立演进,也是后面理解 Socket 和系统调用的基础。

2.2 TCP/IP模型为什么是事实标准

OSI 是理论模型,而 TCP/IP 是工程中真正跑起来的四层模型:数据链路层、网络层、传输层、应用层。它把 OSI 的物理层和数据链路层合并,把上三层会话、表示、应用合并。合并的原因是:下四层处理通信细节,通用且稳定;上三层处理业务细节,差异大,没必要在标准模型里拆那么细。更实际的区别是,上三层通常运行在用户进程内,下四层则作为操作系统内核的一部分,Socket 就是这道边界上的统一接口。

对比两个模型,常见考点如下表:

OSI 七层TCP/IP 四层典型协议
应用层、表示层、会话层应用层HTTP、DNS、FTP
传输层传输层TCP、UDP、SCTP
网络层网络层IPv4、ICMP、ARP
数据链路层、物理层数据链路层Ethernet、BPF、DLPI

注意 ARP 在严格分层里位于网络层和数据链路层之间,但在 TCP/IP 参考模型中常归入网络层或链路层,面试时把这点说清楚会加分。TCP/IP 的工程价值在于它定义了主机如何接入互联网,而 OSI 更像一本教科书,两者关系经常被拿来考察候选人对“理论与工程”边界的理解。

2.3 用tcpdump验证分层模型的实际报文

只看图不抓包,分层永远是抽象概念。常见做法是使用 tcpdump 在本地环回口或物理网卡上抓取访问某个 TCP 端口的流量,观察协议栈实际封装的字段。

sudo tcpdump -i eth0 -nn -S 'tcp port 80' -c 3

参数含义:-i eth0指定抓包网卡;-nn不对 IP 和端口做反向解析,让输出更清晰;-S打印绝对序列号而不是相对序列号,方便观察握手时序列号的变化;tcp port 80是 BPF 过滤表达式;-c 3抓到 3 个包后自动退出。

抓到的包会以以太网头(源 MAC、目的 MAC、类型)开始,接着是 IP 头(源地址、目的地址、协议号),再往下是 TCP 头(源端口、目的端口、序列号、标志位)。这三段正好对应数据链路层、网络层、传输层。如果加上-A,还能看到 TCP payload 里的 HTTP 文本,那就是应用层数据。一次抓包,四层分层直接摆在眼前。很多面试题让你“简述一个数据包的封装过程”,实际动手抓一次,比背十遍七层模型都记得牢。

3. TCP连接管理:三次握手、四次挥手与状态机

3.1 三次握手:建链的必然性

TCP 是面向连接的可靠协议,连接建立过程称为三次握手。客户端先调用 connect 发起主动打开,此时发送一个 SYN 分节,不携带数据,只包含序列号;服务端在 listen 后收到 SYN,回复 ACK 确认客户端序列号,同时携带自己的 SYN 和初始序列号;最后由客户端再回复一个 ACK。很多资料把第二步合并描述为 SYN+ACK,是因为服务端在两个方向上同时应答,无需拆成两次。

为什么是三次而不是两次?关键是为了让双方确认彼此的发送能力和接收能力。假如只有两次,服务端无法确认客户端是否收到了自己的 SYN;假如只有一次,客户端无法确认服务端是否存在。三次握手后,双方都得出一条结论:我能发的你能收,你能发的我能收。初始序列号是随机生成的,防止旧连接的数据串扰新连接,这也是为什么每次抓包看到的 SYN 序列号都不同。

3.2 四次挥手:全双工下的关闭逻辑

TCP 是全双工的,双方各自独立发送数据,因此关闭时也要独立结束各自方向的发送。主动关闭方调用 close 发送 FIN,被动关闭方收到后先回 ACK,然后把接收到的数据以 EOF 形式递交给上层应用;等上层应用也决定关闭,再发送自己的 FIN;最后主动关闭方回 ACK 完成关闭。这就是四次挥手。整个过程可以被分成两个半关闭阶段:收到 FIN 后的连接仍然允许被动关闭方向主动关闭方发送数据,直到它自己也 close。

这里常被追问:为什么三次握手可以合并 ACK 和 SYN,四次挥手却要把 ACK 和 FIN 分开?答案就是全双工。建链时,服务端一旦收到 SYN,就确定客户端发了什么,自己的初始序列号也可以立刻生成,所以能同步应答;断开时,被动关闭方收到 FIN 只是表示“我不会再发数据了”,但自己是否还有数据要发完全取决于上层应用,不可能在收到 FIN 的瞬间就决定关闭,必须等应用处理完,因此 ACK 和 FIN 必然分开发送。

3.3 TCP状态机与关键状态

TCP 连接使用状态机管理生命周期。服务端从 CLOSED 到 LISTEN,收到 SYN 进入 SYN_RCVD,收到 ACK 后进入 ESTABLISHED。客户端从 CLOSED 发送 SYN 进入 SYN_SENT,收到 SYN+ACK 后也进入 ESTABLISHED。断开时,主动关闭方依次经历 FIN_WAIT_1、FIN_WAIT_2、TIME_WAIT,然后回到 CLOSED;被动关闭方经历 CLOSE_WAIT、LAST_ACK。

面试常考的状态如下表:

状态所在端含义
LISTEN服务端正在监听端口,等待连接
SYN_SENT客户端已发送 SYN,等待确认
SYN_RCVD服务端收到 SYN,并回复 SYN+ACK
ESTABLISHED双方连接已建立,可传数据
FIN_WAIT_1主动关闭方已发送 FIN,等待 ACK
FIN_WAIT_2主动关闭方已收到 ACK,等待对方 FIN
CLOSE_WAIT被动关闭方收到 FIN,已回 ACK,等待应用 close
LAST_ACK被动关闭方应用已 close,发送 FIN,等待最终 ACK
TIME_WAIT主动关闭方连接已关闭,等待 2MSL 后消失

注意 CLOSING 状态也会出现在双方同时 close 的场景,但实际业务中较少见,掌握上表已经可以应对绝大多数提问。TIME_WAIT 那个“主动关闭方”最容易记混,动手抓一个包就很清楚。

3.4 用Python和ss命令观察状态跳转

理论知识用命令验证,才能留下肌肉记忆。这里用 Python 起一个最简单的 TCP 服务端,然后通过ss观察连接状态变化。

import socket import time srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM) srv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) srv.bind(('0.0.0.0', 9000)) srv.listen(5) print('listening on 0.0.0.0:9000') conn, addr = srv.accept() print('accepted from', addr) time.sleep(10) # 保持连接,方便观察 ESTABLISHED conn.close() srv.close()

运行后,在另一个终端执行ss -tan | grep 9000,会先看到 LISTEN。当客户端用nc 127.0.0.1 9000或 telnet 连接时,再执行ss -tan | grep 9000,你能同时看到对端的 ESTABLISHED。在服务端 sleep 期间杀掉客户端进程,连接会迅速变成 FIN_WAIT_1 或 TIME_WAIT,取决于谁先 close。ss -tan-t只看 TCP,-a显示所有状态的连接,-n不做解析。实际排查问题时,ss -tan state time-wait能直接列出所有处于 TIME_WAIT 的连接,比 netstat 输出更直接。这里SO_REUSEADDR允许端口在 TIME_WAIT 期间重用,避免脚本反复重启时报地址占用错误,是写网络服务时的常见做法。

4. 可靠传输机制:超时重传、快速重传与ARQ协议

4.1 可靠传输的基本盘:ACK、序列号与重排

网络传输不是直接一条管道,数据包可能走不同路径,先后顺序会被打乱,甚至会丢。所谓可靠,不是百分之百不丢,而是通过机制的组合,让上层感知到异常并进行恢复。TCP 的可靠传输建立在四个机制上:ACK 确认、序列号、重排和窗口。发送方每发一个分节,都会要求接收方回 ACK;每个分节都带字节流偏移量的序列号,接收方据此排序和去重。乱序分节会先缓存,等缺失的补上再交给上层。窗口则同时服务流量控制和拥塞控制。

理解可靠传输有个误区:以为 TCP 保证一定送达。它实际上只是“尽力并反馈”,如果重传若干次仍然失败,连接会终止,上层会收到错误。这和 UDP 的“发出去就不管”有本质区别,也是面试里对比 TCP/UDP 时最常提到的点。

4.2 超时重传和快速重传的触发条件

超时重传是发送方在发送后启动一个定时器,如果超过 RTO 还没收到 ACK,就认为数据丢了并重传。它的缺点是必须等超时,网络越拥塞,越等越久。快速重传则利用接收方的重复 ACK:接收方收到乱序包时,会立刻重发期望的那个序列号的 ACK,连续收到 3 个重复 ACK 时,发送方不等定时器超时,立即重传丢失的分节。

为什么是 3 次重复 ACK?因为网络拥塞可能导致单个包乱序,一两次重复 ACK 可能只是排序抖动,三次就大概率是丢了。这样的设计避免因偶发乱序而频繁重传。快速重传把恢复时间从 RTO 量级缩短到一个 RTT 量级,对实时交互场景提升明显。实际线上如果看到netstat -sretransmits数值持续增长,就是重传机制在兜底,你需要看是超时重传多还是快速重传多,两者指向的网络问题不同。

4.3 ARQ协议的三种模式:停等、GBN与选择重传

ARQ(Automatic Repeat reQuest)是可靠传输的经典实现,TCP 沿用了其确认和重传思想。三种模式各有适用场景,选择重传是复杂度和丢包效率之间的平衡点。停等 ARQ 每发一个包就停下来等待 ACK,吞吐受限于传播时延;Go-Back-N 允许连续发送,但丢一个包会把后续所有未确认分组重传一遍;Selective Repeat 只重传确实丢失的那几个分组,但接收方要缓存乱序数据。用一张表可以直观对比:

模式发送方式重传范围缺点
停等 ARQ发一个等一个 ACK丢失的那个包等待时间长,吞吐低
Go-Back-N连续发送窗口内包丢失包及其后所有未确认包大窗口下重传浪费
Selective Repeat连续发送窗口内包仅重传丢失/损坏的包接收方缓存和序号管理复杂

Go-Back-N 里接收方丢弃所有乱序包,只按序接收;Selective Repeat 接收方缓存乱序包,等缺口补齐后一次性交付。Kafka 在应用层做消息一致性时也用了类似 Continuous ARQ 的思路,用累积 ACK 和反馈机制确保消息不丢,可见这套思想不止存在于协议栈。TCP 实际采用的是 ARQ 的变体,综合了累积确认、选择重传和动态窗口,这也是它能在复杂互联网环境下保持高吞吐的原因。

4.4 RTT估算与RTO调整

RTO 不能拍脑袋定。发送方通过 RTT(往返时间)动态调整超时。RTT 由三部分构成:链路传播时间、末端系统处理时间、路由器排队时间。前两者相对固定,排队时间随拥塞变化,所以 RTT 能反映网络拥塞。RTO 一般不小于 RTT 的 1.5 倍,太小容易频繁重传,太大会让恢复变慢。协议栈里的 RTO 是动态估算的,不是固定值。

工程上可以用 ping 估算当前 RTT 基线:

ping -c 30 192.168.1.1 | tail -1

输出中可以看到 min/avg/max 三个值。估算数据传输时间时可以用平均 RTT。假设平均 RTT 是 175ms,要发送 2000 字节,每次只发 40 字节,则需要 50 次;每个分节带 20 字节 IP 头和 20 字节 TCP 头,总线上每次实际传 80 字节。粗略耗时就是 175ms×50=8750ms。这个估算把协议头开销和往返次数都算进去了,能帮助你判断一个应用为什么慢——很多时候不是带宽不够,而是交互次数太多。

5. TIME_WAIT、端口号与连接数上限:高并发场景的真实约束

5.1 TIME_WAIT为什么必须存在

TIME_WAIT 是主动关闭方在收到最终 ACK 后进入的状态,持续 2MSL(最大分节生命周期)。两个原因:第一,保证最后那个 ACK 丢失时能重传——如果直接进入 CLOSED,对端重发的 FIN 就没人应答,连接无法可靠终止;第二,让旧连接在网络中的重复分节彻底消逝,防止相同 IP 和端口的新连接收到旧数据。MSL 在不同系统不同,Linux 上通常取 30 秒到 1 分钟,因此 TIME_WAIT 会持续 1~4 分钟。很多线上服务大量出现 TIME_WAIT,就是因为短连接都在主动关闭,属正常现象,除非数量过多导致端口耗光。

5.2 端口号的分配范围与套接字对

TCP、UDP、SCTP 都使用 16 位端口号,范围 0~65535,不同协议间的端口号不冲突,因此可以同时监听 80/TCP 和 80/UDP。端口有约定俗成的分配:

范围用途例子
0~1023公共服务,需特权22/SSH、80/HTTP
1024~49151注册服务监听8080/Web 服务
49152~65535临时端口客户端发起连接时自动分配

不同系统临时端口的起始值可能不同,Linux 一般在 32768 以上。一个 TCP 链路用四元组唯一标识:本地 IP、本地端口、远端 IP、远端端口。客户端发起连接时,协议栈自动从临时端口范围挑一个端口,对端 IP 端口是固定的,所以同一客户端默认最多同时建立一个目标端口的连接数约为临时端口数量。这也是为什么高并发下要特别注意 TIME_WAIT 堆积。

5.3 百万连接怎么突破端口限制

经典面试题:固定数量客户端连同一个服务器,如何达到百万连接?很多人卡在“单机端口最多 65535”。实际上端口只是四元组中的一个维度。假设客户端机器固定、服务器 IP 和端口也固定,那么一个客户端进程的源端口范围确实受限;但服务器完全可以通过多个端口监听,每个端口接受一组客户端连接。比如一个目标端口对应 6 万多个客户端连接,开 20 个端口,百万连接就突破了。更大的意义在于,四元组中任意一个元素变化都能扩展连接空间。理解这一点,才不会被“65535 上限”唬住。

5.4 用系统命令定位端口和连接瓶颈

排查端口和连接问题时,常用这几条命令:

cat /proc/sys/net/ipv4/ip_local_port_range ss -tan state time-wait | wc -l ulimit -n

第一条查看本机临时端口范围,比如输出32768 60999,说明可用临时端口约 28232 个。第二条统计 TIME_WAIT 数量,如果持续接近临时端口上限,新连接就会失败。第三条查看进程可打开的文件描述符上限,因为每个 socket 也是一个文件句柄。三条命令一起看,基本能定位“connect 失败”是端口不足还是句柄不足。如果要进一步压低 TIME_WAIT,可以开启net.ipv4.tcp_tw_reuse,但要先确认场景是否安全——它只对出站连接生效,不是万能解药。

6. 把TCP知识落到实战:观察RTT、调整缓冲区与排查异常

6.1 用ss读取实时RTT和拥塞窗口

ping测的是 ICMP 的 RTT,和 TCP 连接的实际 RTT 有偏差。更直接的办法是用ss -tin查看现有 TCP 连接的传输参数:

ss -tin | grep -A 1 '<server_ip>:9000'

输出中会有rtt:0.234rto:0.468snd_cwnd:10这类字段。rtt是当前估算的往返时间,rto是重传超时,snd_cwnd是拥塞窗口。如果连接建立后snd_cwnd一直很小,说明处于拥塞避免阶段,可能网络丢包在限制发送速率;如果rto很大,说明 RTT 波动剧烈。结合上一章的 ARQ 概念,这里的snd_cwnd就是发送窗口的实际体现,窗口不增长时,重传次数再多也没用。

6.2 调整缓冲区观察吞吐变化

发送和接收缓冲区默认值对高吞吐场景影响明显。查看当前缓冲区:

sysctl net.ipv4.tcp_rmem net.ipv4.tcp_wmem

三个数字分别是最小、默认、最大值。临时调大接收缓冲区:

sysctl -w net.ipv4.tcp_rmem='4096 87380 6291456'

调整后重新跑传输测试,观察吞吐是否提升。注意缓冲区和通告窗口挂钩,调大接收缓冲区才能让对端发得快。这个技巧排障时很有用:如果应用吞吐上不去,先看ss -tinsnd_cwnd是否被窗口卡住,再看接收缓冲区是否偏小。把这两步做完,很多“TCP 慢”的问题就不再是玄学。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询