干网络这行,TCP/IP 协议栈是绕不开的基础。不管是排查一台上不了网的电脑,还是定位两台服务器之间的吞吐瓶颈,最终都要回到这四层模型上来重新捋一遍。这篇文章我想从实际使用的角度,把 TCP/IP 模型里每一层到底干什么、数据是怎么一层层包进去再拆出来的、以及 Windows 系统上怎么做端到端的发包收包验证,一次性讲清楚。适合刚入行的网工、运维,也适合写网络应用的开发同学——你跟别人联调接口对不上时,很多时候不是代码问题,而是跨层参数没对上。
1. 不是背公式,先把 TCP/IP 当成一个快递系统来理解
1.1 为什么需要分层这样设计
很多人一上来就背“应用层、传输层、网络层、网络接口层”,背完就忘,因为不知道这套分层设计到底要解决什么问题。其实分层这件事,和你在快递站寄包裹是同一个逻辑:你和快递员各管一段,彼此不需要懂对方手里的全部细节。
寄快递时,你要做三件事:把东西装进箱子(内容),在面单上写清楚寄件人和收件人的姓名、电话(传输层的端口),再写清楚省市区街道门牌(网络层的 IP 地址)。而快递公司负责安排卡车、飞机把包裹从A地运到B地(网络接口层)。每一层只关心自己的那点事,中间某一段换运输方式,比如从陆运转空运,你的面单和箱子内容完全不用变。
TCP/IP 分层也是这个道理。应用层只关心“我说的是什么”,HTTP 也好、DNS 也好,它不关心数据怎么走网线;传输层关心“谁发给谁”,通过端口号区分不同的应用进程;网络层关心“去哪个网段”,通过 IP 地址做路由;网络接口层关心“在物理链路上怎么传给下一跳”,通过 MAC 地址和以太网帧完成收发。四层各有职责,替换任何一层都不影响其他层,这就是它能活几十年的核心原因。
1.2 四层模型和七层模型的实际取舍
老网书会提 OSI 七层模型:物理层、数据链路层、网络层、传输层、会话层、表示层、应用层。TCP/IP 模型简化成四层,工程排错时也基本按这个缩略版来。实际工作中,没人会先分析“会话层出了问题”,你说出这种话,旁边老师傅大概率只是让你先 ping 一下。
OSI 七层和 TCP/IP 四层的对应关系,可以看这个简表:
| OSI 七层 | TCP/IP 四层 | 典型协议/技术 |
|---|---|---|
| 应用层、表示层、会话层 | 应用层 | HTTP、HTTPS、DNS、SSH、FTP |
| 传输层 | 传输层 | TCP、UDP |
| 网络层 | 网络层 | IP、ICMP、ARP(ARP 严格算在链路层之上,常被归到网络层附近) |
| 数据链路层、物理层 | 网络接口层 | 以太网、Wi-Fi、MAC 地址、网卡驱动 |
实际排障时,四层模型已经够用。你在浏览器里看到“无法访问此网站”,心里应该立刻按层过一遍:DNS 解析有没有结果,TCP 三次握手有没有成功,中间路由能不能通,最后才是服务器应用层状态。这套思路就是分层带来的好处。
2. 逐层拆解 TCP/IP 模型:每一层到底在干什么
2.1 应用层:只负责“说什么”,不负责“怎么送”
应用层是离用户最近的一层,也是大家最熟悉的一层。浏览器里的 HTTP 请求、发邮件用的 SMTP、查域名用的 DNS,都属于应用层协议。这一层核心任务是把用户的操作转换成“标准格式的数据”,至于这些数据是被 TCP 可靠送达还是被 UDP 丢了重发,应用层不太关心——那是下面两层的事。
这里有个常见误解:端口号明明是写在数据包里的,为什么算传输层概念?因为端口号确实由 TCP/UDP 头携带。但应用层在“用哪个端口”这件事上有绝对话语权:HTTP 默认 80,HTTPS 默认 443,DNS 默认 53。你可以理解成:传输层提供 65535 个门牌号,应用层决定把哪封信放到哪个门牌下。Socket 就是 IP 地址加端口号的组合,一个“小区定位 + 门牌号定位”,网络世界里的进程通信全靠这对组合。
应用层的排障,最常见的就是 DNS 问题。你在浏览器里输入一个域名,系统先去问 DNS 服务器这个域名对应哪个 IP,如果这一步卡住,浏览器表现就是“转圈半天然后报错”,但此时网络本身可能完全正常。所以判断应用层故障前,先确认一下域名解析是否成功,这事一句话就能完成:nslookup www.example.com。
2.2 传输层:端口、序列号和可靠传输的真正起点
传输层是 TCP/IP 协议栈里最“有故事”的一层。TCP 和 UDP 是两种完全不同的思路,打个比方:TCP 是挂号信,每一封都要收件人签字回执,丢了要补发,顺序乱了要重排;UDP 是明信片,写完扔进邮筒就不管了,能不能到、先到后到,全看运气。
TCP 的可靠性不是靠“多转发几次”实现的,而是靠一套精心设计的机制:建立连接要三次握手,传输数据每个字节都有序号,收方要回 ACK 确认,发送方有超时重传和快速重传,还有滑动窗口控制发送速度。三次握手的三个包特别直观:客户端发 SYN 包(请求建立连接),服务端回 SYN+ACK(收到请求且同意建立),客户端再回 ACK(确认收到服务端的确认)。为什么不是两次?因为要确认双方收发能力都正常。一次握手只证明“客户端能发,服务端能收”,三次才能证明双方“既能收也能发”,这套逻辑想通了,后面看抓包时就不会把 SYN 重传误判成攻击。
UDP 就好办多了,没有握手、没有序号、没有确认,包头只有源端口、目的端口、长度和校验和。优点是开销小、延迟低,适合音视频通话、在线游戏这种“旧一点没关系,卡顿才致命”的场景。DNS 查询也用 UDP,因为每个查询就几个字节,不值得为它建立一条 TCP 连接。
传输层排障要看两个核心指标:端口是否监听,连接是否建立。Windows 上一条命令就能看:netstat -ano。如果端口没在监听,问题大概率是服务没起来;如果在监听却连不上,要么防火墙挡了,要么服务绑定的地址不对。
2.3 网络层:IP 地址、路由与分片处理
网络层解决的是“数据包怎么从源主机到目标主机”的全局路径问题。IP 协议负责编址和路由,ICMP 负责网络层诊断。你 ping 一个地址,用的就是 ICMP 协议,它和 TCP 不是一回事——很多人说“能 ping 通就说明网络没问题”,严格说只代表 IP 层可达,不代表 TCP 端口可用。
IP 包头里值得关注的字段有这几个:源 IP、目的 IP、TTL、协议号、标识和片偏移。TTL 是“生存时间”,每经过一个路由器减 1,减到 0 就被丢弃,防止数据包在网络里无限兜圈。Windows 默认 TTL 是 128,Linux 默认是 64,你 tracert 时看到的每一跳,就是在看 TTL 递减的过程。协议号则告诉接收方“这个 IP 包里面装的是 TCP 还是 UDP”,TCP 是 6,UDP 是 17。
路由和分片是网络层的两个重头戏。同一网段内通信,主机直接用 ARP 查对方 MAC 地址,然后封装成以太网帧发出去;跨网段通信,主机把包交给默认网关,由路由器一级一级转。这里有个容易忽略的点:以太网帧的最大长度是 1518 字节,去掉帧头帧尾后,IP 包最大 1500 字节,这就是 MTU。如果上层数据太大,IP 层就要分片。但分片会带来性能问题——一个片丢了整包都废了,所以现代 TCP 干脆在握手时就协商好分段大小,让 IP 层少干活。TCP 的 MSS 默认就是 1460 字节,也就是 1500 减去 20 字节 IP 头再减去 20 字节 TCP 头,这样正好塞进一个标准以太网帧,不需要 IP 分片。
2.4 网络接口层:从帧到比特的最后一百米
网络接口层是 TCP/IP 模型里最“接地气”的一层,它负责把 IP 包变成能在网线上跑的以太网帧,再从网线上把比特收回来。这一层核心有两个东西:MAC 地址和以太网帧格式。
MAC 地址是网卡的物理地址,48 位,出厂时烧录,理论上全球唯一。IP 地址描述“逻辑位置”,MAC 地址描述“物理身份”,两者通过 ARP 协议互相映射。主机要发数据给同网段另一台主机时,先查自己的 ARP 缓存,没有就广播一条“谁是 192.168.1.100,请把你的 MAC 告诉我”,目标主机回复后,源主机把 IP 和 MAC 的对应关系缓存下来,一般缓存几分钟到几小时。
以太网帧的格式值得扫一眼:目的 MAC(6 字节)+ 源 MAC(6 字节)+ 类型(2 字节)+ 数据(46~1500 字节)+ 帧校验(4 字节)。交换机转发数据就是靠查帧里的目的 MAC 地址,维护一张 MAC 地址表,也叫 CAM 表。这块和路由的概念容易混淆:路由器根据 IP 地址选路,然后改写 MAC 地址把帧从对应端口发出去;交换机只认 MAC,不做跨网段路由。
3. 数据在 TCP/IP 模型中传输的完整旅程
3.1 一次 HTTP 请求从输入到封装的全程
把理论落到实际,最直观的案例就是浏览器访问一个网页。假设你输入http://192.168.1.10/index.html,这里省略 DNS 解析(直接用 IP),数据包的旅程是这样的:
- 应用层把
GET /index.html HTTP/1.1这个请求按 HTTP 格式组织好,交给传输层。 - 传输层(TCP)给这段数据加上 20 字节 TCP 头,包含源端口(随机高位端口,比如 50000)、目的端口(80)、序列号、ACK 号、窗口大小等,形成 TCP 段。
- 网络层(IP)再给 TCP 段加上 20 字节 IP 头,包含源 IP(你的本机 IP)、目的 IP(192.168.1.10)、TTL、协议号 6,形成 IP 包。
- 网络接口层给 IP 包加上 14 字节以太网帧头(目的 MAC、源 MAC 和类型字段)和 4 字节帧校验,形成以太网帧,从网卡发出去。
这个过程画成表格更清楚:
| 阶段 | 数据形态 | 增加的头部 | 关键字段 |
|---|---|---|---|
| 应用层处理完 | HTTP 请求数据 | 无(应用层协议头算在数据里) | GET 请求行、Header、Body |
| 传输层封装后 | TCP 段 | TCP 头 20 字节 | 源端口 50000、目的端口 80、SEQ、ACK、Window |
| 网络层封装后 | IP 包 | IP 头 20 字节 | 源 IP、目的 IP、TTL=128、协议号=6 |
| 网络接口层封装后 | 以太网帧 | 帧头 14 字节 + 帧尾 4 字节 | 目的 MAC、源 MAC、类型 0x0800 |
发出去之前,TCP 还要先完成三次握手,确保服务端 80 端口是开的。所以你在抓包里看到的顺序是:先有 SYN、SYN-ACK、ACK 三个握手包,然后才是那个GET /index.html的数据包。
3.2 链路上交换机、路由器的转发与解封装
以太网帧从你的网卡出来后,第一站是交换机。交换机收到帧,只关心目的 MAC 地址:在自己的 MAC 地址表里查,查到就单播转发到对应端口,查不到就广播到所有端口(除了接收口)。交换机全程不碰 IP 头和 TCP 头,所以交换机不关心你访问的是哪个 IP、哪个端口——这也是为什么交换机配置里看不到“路由”两个字。
如果目标主机在另一个网段,帧会先到达你的默认网关(路由器)。路由器收到帧后,拆掉以太网帧头,露出 IP 包,查看目的 IP,在自己的路由表里找到下一跳出口,然后把 IP 包重新封装成新的以太网帧——注意,源 MAC 会改成路由器出口端口的 MAC,目的 MAC 会改成下一跳设备的 MAC,但源 IP 和目的 IP 始终不变。这就是“路由改 MAC 不改 IP”的口诀来源。
到达目标主机后,解封装是从下往上的逆过程:网卡收到帧,去掉帧头帧尾交给 IP 层;IP 层看目的 IP 是不是自己,是,就去掉 IP 头交给 TCP 层;TCP 层校验序列号,把数据按序组装好交给应用层。整个过程有几次头部移除,数据本体一直没变。理解这套流程后,你就明白为什么抓包时看到 “TCP Retransmission” 不一定是丢包——也可能是接收方的 TCP 缓冲被占满,被迫丢弃后续数据。
3.3 可靠传输背后的确认和重传机制
TCP 的可靠性建立在“序号 + 确认 + 重传”这个三角关系上。发送方给每个字节编号,比如发送 1000 字节,序号从 1 到 1000,接收方收到后回一个 ACK,这个 ACK 号表示“我期待下一个字节的序号”,也就是 1001。如果发送方在超时时间内没收到 ACK,就把这段数据重发一次。
更高效的重传是快速重传:如果接收方收到一个乱序的包,比如期望序号 1001,却收到了序号 2001 的数据,它会立刻回一个 ACK=1001(确认序号不变,表示“我还在等 1001”)。发送方连续收到三个相同的 ACK=1001,不用等超时,立刻重发序号 1001 的数据。这就是抓包里看 DUP ACK 的含义。
滑动窗口则解决了“发多快”的问题。接收方在 TCP 头里通告自己的接收窗口(Window),告诉发送方“你最多可以给我发这么多字节,不用等确认”。如果接收方处理不过来,窗口就会变小,发送方就自动放慢速度。这就是 TCP 的流控——它不靠暴力限速,而是靠对端反馈动态调整。理解了这几个机制,再去看 Wireshark 里那些 Expert Info 提示,至少能分清“这是丢包导致的重传,还是乱序导致的确认异常”。
4. Windows 系统下端到端 TCP/IP 发包收包实测
4.1 Windows 自带的网络诊断工具使用清单
Windows 系统里其实藏着一整套 TCP/IP 排障工具,只是很多人只知道 ping。这里列一份我平时用得最频繁的工具清单,每个工具解决一个层面的问题:
| 工具 | 作用层面 | 典型命令 | 适用场景 |
|---|---|---|---|
| ipconfig | 网络层/IP 配置 | ipconfig /all | 查看 IP、子网掩码、网关、DNS、MAC 地址 |
| ping | 网络层/ICMP | ping -t 192.168.1.1 | 测试到目标是否连通、延迟多大 |
| tracert | 网络层/路由路径 | tracert www.example.com | 定位卡在哪一跳,查看路由是否走错 |
| pathping | 网络层+链路质量 | pathping 192.168.1.1 | 统计每一跳的丢包率,比 tracert 更详细 |
| route print | 网络层/路由表 | route print -4 | 查看默认路由是否正确、有没有多余路由 |
| netstat | 传输层/端口状态 | netstat -ano | 查看端口监听状态,定位 PID 对应的进程 |
| Test-NetConnection | PowerShell 全能测试 | Test-NetConnection 192.168.1.10 -Port 80 | 相当于集成版 telnet,测试 TCP 端口是否能通 |
| getmac | 链路层 | getmac /v | 查看本机各网卡的 MAC 地址 |
重点说下Test-NetConnection,如果你在用 PowerShell 的话,这个命令效率极高。Test-NetConnection www.baidu.com -Port 443会同时返回 DNS 解析结果、目标 IP、Ping 结果和指定端口的 TCP 连接测试结果,不用再一个一个敲命令拼信息。
4.2 用 iperf 实测两台 Windows 主机的收发吞吐
ping 只能测到目标能不能通,但测不出网络的真实吞吐能力。想确认两台机器之间的 TCP/IP 传输实际能达到多大带宽,标准做法是用 iperf 打流。
先准备两台 Windows 机器,一台当服务器,一台当客户端。iperf3 的 Windows 版本从官网下载解压就行,是个免安装的 exe 文件,不需要额外安装依赖。服务端执行:
iperf3.exe -s -p 5201-s表示服务端模式,-p 5201指定监听端口。客户端执行:
iperf3.exe -c 192.168.1.10 -t 60 -i 5 -P 4-c后面跟服务端 IP,-t 60表示测试 60 秒,-i 5表示每 5 秒打印一次结果,-P 4表示用 4 个并行连接同时打流,能把多核网卡的吞吐潜力压出来。跑完客户端会显示每个连接的平均带宽和汇总值。
这里有几个实测中容易踩的坑。第一,Windows 防火墙默认会拦截 iperf 的 5201 端口,服务端需要提前放行:netsh advfirewall firewall add rule name="iperf" dir=in action=allow protocol=TCP localport=5201。第二,iperf3 和 iperf2 协议不兼容,两台机器必须用同一个大版本,否则客户端连接后看不到任何数据。第三,测吞吐前先确认两端网卡的协商速率:任务管理器—性能—以太网里看链接速度,如果显示 100 Mbps 而不是 1 Gbps,问题多半在网线或交换机端口,不是 TCP/IP 参数的问题。
一次正常千兆测试的预期结果大约是 900 Mbps 到 940 Mbps 左右,这是 TCP 协议开销的物理上限。如果测出来只有 5 Mbps,且测试输出里出现大量重试,那就要借助抓包来看丢包到底发生在哪一段了。
4.3 用 Wireshark 抓包验证 TCP 三次握手和捭包过程
Windows 下抓包工具首推 Wireshark,配 Npcap 抓包驱动。安装完成后,打开 Wireshark,选择上网的那块网卡(名字一般是“以太网”或“WLAN”),点击开始捕获,然后去浏览器访问一次目标网站,就能看到一串 TCP 包。
先在过滤栏输入tcp.port == 80过滤出 HTTP 流量,再输入tcp.flags.syn == 1过滤出 SYN 包,就能清晰看到三次握手的三个包:第一次是本地 IP 发往服务器 IP,标志位 SYN,序列号是一个随机初始值;第二次是服务器回包,标志位 SYN+ACK,序列号是服务器的随机值,ACK 号是客户端的初始序列号加 1;第三次是客户端回 ACK,序列号是客户端初始号加 1,ACK 号是服务器初始号加 1。
看序列号的变化是理解 TCP 的关键。初始序列号看起来毫无规律,是因为现代 TCP 栈做了随机化,防止老连接的数据包污染新连接,这属于正常设计,用不着觉得奇怪。抓包时还会看到一些红色标注的 “TCP Retransmission” 或 “TCP Out-of-Order”,新手会慌,其实先看上下文再下结论:一个重传包出现,要看它前面是不是丢了 ACK,还是这个包本身真的丢了,配合 TCP 的 StreamGraph(统计—TCP 流图—时间序列图)能直观看出丢包点。
抓本机回环流量(比如访问本机部署的网站)时有个小坑:Windows 上 Npcap 默认能抓回环,但需要在 Wireshark 里选“Npcap Loopback Adapter”或“Adapter for loopback traffic capture”这个虚拟接口,而不是“以太网”接口。选错了会看到接口列表里根本没有你的回环流量。
5. 常见问题与排查技巧实录
5.1 高频故障排查速查表
结合前面的内容,把日常遇到最多的几类问题整理成一张速查表,照着顺序查就够:
| 现象 | 检查顺序 | 常用命令 | 常见根因 |
|---|---|---|---|
| 完全上不了网 | 网卡状态 → IP 配置 → 网关 → DNS | ipconfig /all、ping 网关、ping 8.8.8.8 | DHCP 获取失败、网线松动、网关宕机 |
| 能 ping 通 IP,但访问不了域名 | DNS 解析 | nslookup www.example.com | DNS 服务器不可用、DNS 缓存污染 |
| 能上微信/QQ,但网页打不开 | TCP 80/443 端口、HTTP 代理 | Test-NetConnection www.example.com -Port 80 | 代理设置有问题、防火墙封了网页端口 |
| 局域网内互相 ping 不通 | ARP、VLAN、防火墙 | arp -a、ping 同网段IP | Windows 防火墙开了“阻止所有传入连接” |
| 延迟忽高忽低 | 链路质量、无线信号 | pathping 目标IP | Wi-Fi 干扰、网线质量差、广播风暴 |
| 下载速度远低于带宽 | TCP 窗口、网卡协商 | iperf3 打流、任务管理器看链接速度 | 网线只通了 4 芯、路由限速、NAT 性能瓶颈 |
5.2 几个容易误解的 TCP/IP 细节
第一,“能 ping 通”不等于“能建立 TCP 连接”。ping 走的是 ICMP,服务端即使不运行任何服务(比如 80 端口没监听),也会正常回 ICMP。判断服务是否可用,必须测 TCP 端口,用Test-NetConnection比用 ping 靠谱得多。
第二,“看到 TCP Retransmission”不等于“网线断了”。重传是 TCP 的自我修复机制,和丢包率相关。阈值的经验值是:千兆链路打流时重传率低于 0.1% 属于正常;如果超过 0.5%,就要看是不是网卡驱动开了太多中断合并导致缓冲溢出,或者链路本身有误码。
第三,“回环 ping 通”只说明协议栈没问题。ping 127.0.0.1的数据包根本不经过网卡和物理链路,它验证的是从应用层到网络接口层的 IP 协议栈是否被正确加载。它在 Windows 上如果失败了,一般意味着 TCP/IP 栈损坏,可以尝试用netsh int ip reset重置,但别把它当成网络连通性的证明。
第四,防火墙的状态影响容易被忽略。Windows 防火墙在默认配置下允许出站流量,但服务器场景里如果改成“阻止所有传入连接”,即使服务本身在监听,外部也无法访问。排障到这一步时,优先检查防火墙再检查代码,能省下大量时间。
5.3 抓包和打流实验的个人经验心得
我做过的 TCP/IP 实测里,最有价值的一件事就是把 Windows 本机、一台交换机和一台 Linux 服务器串起来,跑通“ping 网关 → ping 服务器 IP → iperf 双向打流 → 抓包看三次握手”这条完整链条。整个过程下来,对分层模型的理解比看了十遍书都深刻。
抓包时我一般遵守三条个人原则。第一,先用捕获过滤器圈定范围,比如只抓特定主机host 192.168.1.10或特定端口tcp port 5201,因为大流量环境全量抓包会把磁盘写满,也会让 Wireshark 卡成幻灯片。第二,先看 TCP 错误标记,比如 Expert Info 里的黑底红字项目,再顺着时间线看上下文,最后才看数据内容,顺序反了容易被大量正常流量淹没。第三,分析吞吐问题时,除了看重传,还要看 TCP Window 有没有被打满,如果窗口一直很小,说明接收方处理能力是瓶颈,这时候调发送端参数没用。
iperf 打流测出来的数字也不是绝对的。网络设备上的 QoS 策略、交换机单端口限速、甚至 Windows 的接收侧缩放(RSS)配置都会影响结果。建议多测几轮,先用-P 1测单连接,再-P 4测多连接,对比数据比单次结果更有参考价值。
最后再分享一个小技巧。Windows 内置了netsh trace,一条命令就能启动系统级网络跟踪,同时抓取事件追踪日志和网络数据包,比单独配 Wireshark 在有些场景下更省事。排查周期性网络问题而不想一直挂机抓包时,可以试试netsh trace start capture=yes,问题复现完netsh trace stop,生成的文件可以用 Wireshark 打开,里面的抓包视图和事件日志是联动的,能省去很多从协议栈和系统日志两头找线索的功夫。
TCP/IP 这套东西,说复杂也复杂,说简单也简单。复杂的是它几十年累积下来的细节,比如拥塞控制算法就有 Reno、Cubic、BBR 一堆变体;简单的是它的分层思想——每一层只干自己该干的活,层与层之间通过标准接口协作。你不需要把所有细节都背下来,但你需要亲手抓一次包,亲眼看着三个握手包在 Wireshark 里依次出现,然后顺着数据包一层层拆下去。做完这件事,那些抽象的概念就有了实际的锚点,以后再遇到网络问题,心里不会慌。