搞网络的人,迟早会遇到一个坎:明明设备都配好了,线也插对了,两台机器就是 ping 不通。你抓包看,报文在发,对端却收不到,或者收到了不回。这个时候,光会配 IP 是不够的,你必须要懂数据通信过程——数据到底是怎么从一台设备跑到另一台设备身上的。这个话题我聊过不少次,但每次给新人讲都发现,大家缺的不是单个协议的知识,而是缺一条完整的链路:应用程序发一个字节出去,中间经过了什么,每一层做了什么,路由器交换机分别干了什么,最后接收方是怎么把这个字节还原出来的。
这篇文章就是来把这个过程彻底讲透的。我会从最常用的 TCP/IP 模型出发,把封装、寻址、转发、解封装这条主线串起来,结合抓包和实际场景,让你看完之后脑海里能形成一个完整的数据通信过程画面。不管是刚入行的网络工程师、在校学生,还是做开发想补网络基础的,这篇文章都可以当成一个中长期的参考,遇到问题随时回来翻。
1. 先搞清楚:数据通信到底在“通”什么
1.1 从一次“寄快递”理解端到端通信
很多教材喜欢一上来就讲分层模型,OSI 七层、TCP/IP 四层,背得头大,还是不知道数据是怎么过去的。我换个方式——寄快递。
你网购了一件商品,商家发货,快递员取件,包裹经过好几个中转站,最后送到你家楼下,你拆开包装拿到实物。整个过程里,商家不需要认识每个快递员,你也不需要知道包裹走了哪条高速,中转站只关心下一站往哪儿送,而快递单上的“收货地址”和“收件人电话”决定了包裹最终被谁签收。
数据通信跟这个几乎一模一样。一个应用程序要发数据给另一台机器的应用程序,数据本身要被打包(封装),包裹上要写清源地址和目的地址(IP 地址),到了局域网里还要有更细的标识来定位具体某个网卡(MAC 地址),中间经过各种网络设备(交换机、路由器)逐跳转发,最后到达目的主机,一层层拆包(解封装),把数据交给对应的应用程序。
你一旦把数据通信过程想象成物流过程,很多概念就顺了。IP 地址就是收货地址,MAC 地址就是收货人姓名(在同一栋楼里找人具体到人),TCP 端口就是“部门/收件人手机号”,而路由器就是中转站。数据每经过一个中转站,外层的“运输标签”会换,但里面的“货物”始终不变。
用这套类比再去看 TCP/IP 协议栈,就会发现每一层都有明确的职责,各管一段,但又互相配合。
1.2 通信过程的四个基本阶段
完整的数据通信过程,不是一股脑把数据丢出去就完事,而是有节奏地分阶段进行。你说一段话也得先打招呼、然后说正事、中间确认对方听懂了、最后说再见,网络通信也是同样的道理。一次完整的 TCP 通信,大致可以拆成四个阶段:
- 建立连接阶段:双方确认“我在、你在、咱们可以聊了”,对应 TCP 三次握手。
- 数据传输阶段:数据按序发送,接收方确认收到,没收到或错了就重传,对应滑动窗口、确认应答、超时重传等机制。
- 连接保活与状态维护:通信双方维护各自的连接状态,通过定时器感知链路是否存在,防止半开连接一直占资源。
- 释放连接阶段:双方确认数据都发完了,正式道别,对应 TCP 四次挥手。
这四个阶段是理解一切网络问题的骨架。你排查一个“连接建立不了”的问题,首先得判断卡在哪个阶段:是握手没完成,还是数据传输出错,还是连接释放异常。有了阶段概念,就不会眉毛胡子一把抓。
大多数 TCP 通信问题的根因,都可以归结为四个阶段中的某一个出了问题。比如最常见的“连接超时”,基本就是握手阶段 SYN 发出去没有回应;“传着传着断了”,通常是传输阶段的保活或确认机制触发了异常;“大量 TIME_WAIT 堆积”,则跟释放阶段的挥手过程密切相关。
1.3 数据通信中的三个关键参与者
整个数据通信过程中,真正干活的角色其实只有三类:源设备(发送端)、中间网络设备、目的设备(接收端)。但对中间网络设备,很多人会混淆交换机、路由器的分工。
给你一个特别干脆的判断方式:交换机工作在二层,根据 MAC 地址转发;路由器工作在三层,根据 IP 地址转发。前者就像小区物业,知道每个住户住哪栋楼哪个单元,负责楼内送货;后者就像城市的物流分拨中心,只看你的目的城市和街道,决定把货甩给哪个下一站。
不过现在的三层交换机、高端路由器功能越来越重合,让这个概念变得模糊。但你要记住:在讨论标准的数据通信过程时,二层的转发决策和三层的路由决策是两个独立的逻辑环节,不能混为一谈。理解分层再去看那些“三层交换机”怎么同时干两种活,就不会绕晕。
源设备负责把用户数据层层“打包”并发送,目的设备负责接收并逐层“拆包”,而中间设备并不关心你传输的数据内容是什么,它们只做一件事——根据自己所在层的信息,把数据尽量快、尽量准地送到下一跳。这个“各管一层”的设计,就是整个互联网能跑起来的基石。
2. 数据的“包装”过程:封装与解封装
2.1 从上到下逐层封包,从下到上逐层解包
两个应用程序要通信,数据不可能光着身子在网络里裸奔,每一层都要给它套一个头。这个过程叫封装。
举个最常见的例子:你在浏览器里访问一个网站,HTTP 请求要发给服务器的 80 端口。数据从应用层往下走:
- 应用层:HTTP 协议把请求数据交给传输层,此时的数据叫“消息(Message)”。
- 传输层:TCP 协议给数据加上 TCP 头部,里面有两个关键字段——源端口和目的端口(比如 54321 → 80),以及序列号、确认号等。加了 TCP 头的数据叫“段(Segment)”。TCP 头的作用是标记“这个数据要给哪个应用程序,以及它在整个数据流中的位置”。
- 网络层:IP 协议再套一层 IP 头,里面最关键的是源 IP 和目的 IP。比如本机 192.168.1.100,目标 93.184.216.34。加了 IP 头的数据叫“包(Packet)”。IP 头的作用是标记“数据要从哪个地址发到哪个地址”。
- 链路层:以太网协议在最前面加一个以太网头,包含源 MAC 和目的 MAC(如果是本网段内通信,目的 MAC 就是目标机器的;如果跨网段,目的 MAC 是默认网关的)。同时帧尾部还有 FCS(帧校验序列)用于检错。这层的数据叫“帧(Frame)”。
每层的头部,都相当于快递单上的一栏信息。TCP 头写“收件人手机号”,IP 头写“收件地址”,以太网头写“当前派送员和下一站派送员”。这一层层往外套的过程,跟套娃一样。
到了接收端,流程正好反过来,从下往上逐层剥掉头部,每剥一层就根据头部信息做判断。先看以太网头里的目的 MAC 是不是自己的(或者广播地址),不是就丢弃;再看 IP 头里的目的 IP 是不是自己的,不是就丢弃或转发;然后是 TCP 头确认端口号是否匹配,最终把载荷交给对应应用程序。这个过程叫解封装。
封装和解封装是整个数据通信过程的核心动作,不管通信链路有多长、设备有多复杂,这两件事每一跳都在重复发生。只不过在中间设备上,部分层的封装会被拆掉重做——比如路由器收到一个帧,会先解开以太网头,看 IP 层信息来决定下一跳,然后重新封装一个新的以太网头发出去。这里有一个极其重要的概念:数据包在每一跳之间,MAC 地址会不断变化,但 IP 地址(在不做 NAT 的情况下)保持不变。后面我讲跨网段通信时会再详细展开。
2.2 TCP 头部与三次握手的核心逻辑
要理解 TCP 头,先抓住最核心的六个字段:源端口、目的端口、序列号(Seq)、确认号(Ack)、标志位(SYN/ACK/FIN 等)、窗口大小(Win)。
三次握手是数据通信过程中用时最短但最关键的环节。它的本质是让通信双方确认两件事:一是彼此的收发能力正常,二是初始序列号(ISN)达成一致。序列号为什么重要?因为 TCP 是面向字节流的协议,数据被切成一段一段发送,接收方要靠序列号把数据按正确的顺序拼回来。如果初始序列号不协商好,后续的“第几段数据”就无从谈起。
抓包的时候看三次握手特别直观:
- 第一次:客户端 → 服务端,
SYN=1, Seq=0,请求建立连接,并告诉对方“我的初始序列号是 0”。 - 第二次:服务端 → 客户端,
SYN=1, ACK=1, Seq=0, Ack=1,回应“收到你的同步请求,我的初始序列号也是 0,我期望你下一个数据包的序列号是 1”。 - 第三次:客户端 → 服务端,
ACK=1, Seq=1, Ack=1,确认“知道了,我开始发数据了”。
注意抓包里 Seq=0、Ack=1 是相对序列号,为了可读性做了偏移,实际抓包可以右键设置相对或绝对显示。三次握手为什么不能省成两次?因为 TCP 要防止历史失效连接请求突然到达服务端,导致服务端白白建立连接。三次握手让服务端在响应后必须等客户端再确认一次,如果客户端发现这个连接的序列号不对,发送 RST 拒绝掉,就能避免错误连接占用资源。这两次确认一来一回的代价,换来了可靠性,很值。
2.3 数据切片、MSS 与 MTU 的关系
数据不是一口气发送的,TCP 会把应用层的数据切成一段一段。切多长?由 MSS(最大报文段长度)决定。MSS 又受到 MTU(最大传输单元)的限制。
标准以太网的 MTU 是 1500 字节,意思是链路层帧的“数据载荷区”最多塞 1500 字节。IP 头和 TCP 头加起来一般是 40 字节(IPv4 无选项、TCP 无选项),所以 MSS 通常是 1500 - 40 = 1460 字节。TCP 发送的数据段加上 TCP 头(20字节)加上 IP 头(20字节)=1500,正好卡在 MTU 以内,不需要 IP 分片。
这里经常踩坑的地方在于:MTU 不一致导致的大包不通。典型的例子就是 PPPoE 拨号网络,PPPoE 头占了 8 字节,实际可用 MTU 变成 1492。如果你的服务器扣着 1500 发大包,经过 PPPoE 链路的时候,要么被分片,要么被丢弃(如果设置了 DF 不分片标志)。表现就是你 ping 小包通、ping 大包不通,网页打不开但微信消息能发出来,因为微信小包多,网页经常有大于 1460 的大包。
MSS 是在 TCP 握手时通过 SYN 报文里携带的 MSS 选项协商的,双方取较小的那个作为发送段大小。所以排查这类问题的时候,可以先抓包看握手报文里的 MSS 是多少,再结合中间链路的 MTU 做判断。关于 MTU 问题我在后面问题排查部分还会展开讲,这里先埋个伏笔。
3. 数据“找路”的过程:寻址与逐跳转发
3.1 MAC 地址与 IP 地址的分工
理解数据通信过程,最绕不开的就是“双地址”体系。为什么有了 IP 地址还要 MAC 地址,不能只用一个?我给你拆开讲。
IP 地址是逻辑地址,是网络层用来做全局寻址的,它描述的是“设备在网络拓扑中的位置”。你可以把 IP 地址想象成“城市 + 街道 + 门牌号”,它负责在整个互联网范围内把数据从一个网络路由到另一个网络。但这个门牌号不是永恒的,设备换了个网络,IP 地址可能就变了。
MAC 地址是物理地址,出厂时烧录在网卡上,理论上全球唯一,是二层设备(交换机)用来在同一个局域网内定位具体端口的。它好比“收件人身份证号”,在同一个小区/大楼里,门牌号可能因为重新编号而变化,但身份证号不变。
通信的时候,数据帧在链路上走,实际的传递是依赖 MAC 地址逐跳完成的;而路由决策依据的是 IP 地址。所以一个完整的数据包,是 IP 头带着“源和目的的门牌号”,以太网头带着“当前这一跳的源和目的身份证号”。每过一跳,以太网头的对应关系就会更换。
很多人刚开始看抓包会被这点绕晕:明明我要访问的是 103.235.46.39 的服务器,为什么在局域网里抓包看到目的 MAC 是路由器而不是那台服务器?就是因为跨网段通信时,数据帧要先交到默认网关手里,由网关负责下一跳转发,所以以太网头的目的是网关的 MAC。理解了这个,你就理解了二层和三层在数据通信过程中的分界线。
3.2 ARP 协议:怎么从 IP 地址查到 MAC 地址
数据要发出去,源设备得先知道“下一跳设备的 MAC 地址”。但这个 MAC 地址怎么拿?靠 ARP 协议。
ARP 的工作方式特别像你在小区门口大喊:“192.168.1.1 是哪位?请把你的身份证号告诉我!”这个“大喊”是广播帧,发到局域网里所有设备。IP 是 192.168.1.1 的设备听到后,会单播回复自己的 MAC 地址。请求方收到后,把 IP 和 MAC 对应关系放进 ARP 缓存表,下次直接用,不用再喊。
用命令行可以随时看 ARP 表:
# Windows arp -a # Linux / macOS ip neigh这里有几个关键细节。第一,ARP 请求是广播(目的 MAC 是 FF:FF:FF:FF:FF:FF),但 ARP 回响应是单播,不会全网都收到。第二,ARP 表有老化时间,一般几分钟,超时会重新做一次 ARP 解析,这是为了确保 MAC 变更能及时被感知。第三,ARP 解析只在同一网段内进行——跨网段通信时,源设备 ARP 解析的目标不是最终服务器,而是默认网关的 MAC。
我在实际工作中遇到过不少“通一半”的诡异问题,最后都跟 ARP 表异常有关。比如设备迁移导致 IP 换了网卡,或者有设备私设 IP 跟别人冲突,ARP 表里存的 MAC 不对,数据就一直发错地方。排查这类问题最直接的办法就是清 ARP 缓存:
# Windows arp -d # Linux ip neigh flush all再重新通信,把正确的 ARP 解析结果刷新进来。
3.3 同网段通信与跨网段通信,路径差异在哪里
同网段通信的完整流程相对简单:
- 源主机检查目的 IP 和自已是否在同一网段(用子网掩码做与运算)。
- 如果同网段,直接发 ARP 请求查目的主机的 MAC。
- 查到后,源主机封装以太网帧,目的 MAC 为目标主机,直接通过交换机转发到目标端口,目标主机解封装,通信完成。
这个过程中交换机扮演的角色是“二层转发”。它维护一张 MAC 地址表,端口 A 收到源 MAC 为 X 的帧,就记录“X 在端口 A”,以后给 X 发数据就往端口 A 送,这叫 MAC 地址学习。如果目的 MAC 未知,交换机会把帧广播到除接收端口外的所有端口,目标设备回包后,交换机就学到了它的位置。
跨网段通信就多了一个“中间人”——默认网关:
- 源主机发现目的 IP 不在同一网段,就把数据包要交给默认网关处理。
- 源主机 ARP 解析默认网关的 MAC,封装帧后发给网关。
- 网关(路由器)解封装到 IP 层,查路由表决定下一跳出口。
- 路由器重新封装以太网头(源 MAC 变成出接口 MAC,目的 MAC 变成下一跳设备的 MAC),把包发给下一跳。
- 这个过程一直重复,直到数据包到达目的主机所在网段的路由器,再由该路由器 ARP 解析出目的主机 MAC,把帧发给目的主机。
全程里,IP 层的源和目的 IP 一直不变,而链路层的 MAC 地址每一跳都在换。抓包观察时,可以沿着路径在不同节点分别抓包,对比以太网头的 MAC 变化,这个现象特别明显。
还有一个容易被忽略的字段——TTL。IP 头里的 TTL(Time To Live)初值通常由操作系统决定(Linux 默认 64,Windows 默认 128,老一些的 Unix 是 255),每经过一个路由器减 1,减到 0 就被丢弃,并回送一个 ICMP 超时消息。防的是数据包在环路里无限打转。用 traceroute 工具查路由路径,靠的就是 TTL 的递减机制。
4. 一次网页访问的完整通信过程复盘
4.1 从浏览器输入网址到 DNS 解析
前面把各个零件拆完了,现在拼起来看一次完整的通信。假设你在浏览器输入www.example.com并回车,整个数据通信过程的起点其实不是发数据,而是“找到目标 IP”。
浏览器要先通过 DNS 协议把域名解析成 IP。本机会先查本地 DNS 缓存,如果缓存里有记录,直接用;没有就去问配置的 DNS 服务器(自动从 DHCP 获取,或手工指定,比如 223.5.5.5)。
如果 DNS 服务器也不在本地,它就要代表你向更上层的 DNS 系统发起递归查询。这个过程也是数据通信,只不过走的是 UDP 53 端口(特殊情况下会用 TCP 53)。DNS 查询报文会像普通数据一样被封装、寻址、转发,最终从 DNS 服务器带回一条应答,里面就有www.example.com对应的 IP。
这里请你注意一个细节:DNS 查询在发起之前,也要先判断 DNS 服务器 IP 是否与本机同网段,不同网段就先 ARP 查询网关 MAC,然后发给网关。也就是说,DNS 解析之前还隐藏了一轮完整的 ARP + 路由转发流程。这就是为什么推荐新手学排错时,先看“能不能 ping 通网关”,网关都不通的话 DNS 想都别想。
4.2 TCP 连接建立与 HTTP 请求/响应
拿到 IP 之后,浏览器和服务器开始进行 TCP 三次握手,建立可靠的传输通道。通道建好后:
- 浏览器构造一个 HTTP GET 请求报文,交给 TCP 层。
- TCP 给请求数据加上 TCP 头,生成一个段,序列号是从握手协商好的初始值开始递增的。
- IP 层封装 IP 头,源 IP 是本机,目的 IP 是服务器 IP。
- 链路层封装以太网头,把帧发给网关(跨网段场景)。
- 帧沿途经过多个路由器逐跳转发,最终到达服务器所在网段。
- 服务器的协议栈逐层解封装,TCP 层确认数据完整性,HTTP 层把请求交给 Web 服务程序。
- Web 服务程序生成 HTTP 响应,按完全相同的流程返回给浏览器。
响应数据的传输过程要应对“大内容”的情况。一个网页可能有几百 KB 甚至几 MB,会被 TCP 切成多个 MSS(1460 字节)大小的段,分别编号发送。接收方按照序列号把乱序到达的段重新组装,同时通过 ACK 告诉发送方“我已收到哪些数据,请继续发哪些”。如果中间的段丢了,接收方会持续对最后一个连续收到的段做重复确认(Dup ACK),发送方据此快速重传。
4.3 连接复用与四次挥手
HTTP 早期版本,每次请求都要新建一个 TCP 连接,效率很低。现在普遍用 HTTP/1.1 的 Keep-Alive 和 HTTP/2 多路复用,多个请求可以在同一个 TCP 连接上并行或串行地完成,有效减少握手开销,避免每次传输都重复经历“建立连接—传输—释放连接”的全流程。
当所有数据传输完成,连接要关闭。四次挥手最直接的理解是“双方轮流说再见”:
- 第一次:主动关闭方发
FIN,表示“我的数据发完了”。 - 第二次:被动关闭方回
ACK,表示“知道了,但我还有数据要发的话你等我”。 - 第三次:被动关闭方也发
FIN,表示“我的数据也发完了”。 - 第四次:主动关闭方回
ACK,表示“好,连接关闭”。
主动关闭方发送最后一个 ACK 后,会进入 TIME_WAIT 状态,等 2MSL(两倍最大报文段生存期,通常 60 秒)才真正释放。这个等待不是为了拖延,而是防最后一个 ACK 丢失导致对方重发 FIN,同时让旧连接的延迟报文在网络里自然消亡。如果服务器上有大量 TIME_WAIT 连接堆积,可以通过调整内核参数优化,但默认的安全处理逻辑不要随便关。
5. 排查通信问题的实战误区与技巧
5.1 抓包之前,先确认网络拓扑与基础连通性
排查数据通信问题,我见过最多的情况是:一上来就抓包,看了一堆报文还是一头雾水。正确姿势应该是先问三个问题:拓扑是什么?路由怎么走?服务监听在哪?这三个问题不搞清楚,抓包就是盲人摸象。
先确认拓扑——源机器到目标机器之间,经过哪些交换机、路由器、防火墙,中间有没有 NAT 转换,有没有负载均衡器。每多一个设备,就多一层排查点。再确认路由——在源机器上执行traceroute(Windows 是tracert),看数据实际走的路由路径跟你预期是否一致。很多时候“以为走的是 A 线路,实际走了 B 线路”,问题就藏在 B 线路上。最后确认服务监听——netstat -tlnp(Linux)或netstat -an一看,服务可能根本没监听在你认为的网卡/IP 上。
这三步做完了,再决定要不要抓包,以及在哪里抓。抓包位置不同,看到的东西完全不同:在源主机上抓,能看到应用层发出的所有流量;在路由器上抓,是转发视角;在目标主机的回环接口上抓,才能确认数据到底有没有到达本机协议栈。
5.2 典型故障速查表与定位思路
下面这些是数据通信过程中最常见的故障,我按“现象 → 可能原因 → 排查命令”整理成一张表,可以收藏备用。
| 现象 | 可能原因 | 排查切入点 |
|---|---|---|
| 同一网段 ping 不通 | ARP 解析失败、目标主机关机、防火墙屏蔽 ICMP | arp -a看有没有目标 MAC;抓包看有没有 ARP 请求和响应 |
| 跨网段 ping 不通网关可达 | 路由器路由表缺失、ACL 过滤、回程路由问题 | traceroute看卡在哪一跳;检查路由器路由表 |
| ping 小包通,大包不通 | MTU 不一致导致分片或丢弃,PPPoE 场景高发 | ping 加-s 1472逐步加大包长;对比握手报文 MSS |
| 连接建立后马上断,反复重连 | 防火墙 RST 注入、TCP 保活超时、服务端 backlog 溢出 | 抓包看谁先发的 FIN/RST;检查服务端ss -s和 accept 队列 |
| 单边通(A 能 ping 通 B,B ping 不通 A) | 回程路由缺失、NAT 配置不对称、单向 ACL | 在 B 上traceroute到 A,对比路径;检查双向 ACL |
| 网页打开极慢,图片加载不出来 | DNS 解析慢、TCP 握手丢包、MTU 问题导致大包重传 | 分段测试:DNS 用dig测耗时;取首包时间;看抓包是否有大量重传 |
这些现象很多是叠加出现的,比如“MTU 问题 + 防火墙丢包”会表现成更复杂的症状。我的经验是:每排查一步就记录一次证据,不要凭感觉猜。抓包文件要保存好,跟同事协同时,别人能根据你的抓包快速定位,而不是重新排查一遍。
5.3 抓包实操:跟踪一次完整的数据通信过程
如果你用的是 Linux,tcpdump 是最趁手的工具。一次完整跟踪可以这样操作:
# 终端1:后台抓包,保存到文件 sudo tcpdump -nn -i eth0 -s 0 -w http_trace.pcap 'tcp port 80 or tcp port 443' # 终端2:发起一次 HTTP 请求 curl -I http://example.com # Ctrl+C 停止抓包后,用 Wireshark 打开文件分析用 Wireshark 打开抓包文件后,重点看这几处:
- 过滤出 TCP 三次握手:显示过滤填
tcp.flags.syn==1,配合时间戳确认握手花了多久。 - 看序列号与确认号:选中任意数据包,看 TCP 头的 Seq 和 Ack 是否连续、有没有跳变。跳变往往意味着重传或丢包。
- 红色标记的重传包:出现大量 TCP Retransmission 时,优先怀疑链路质量问题或 MTU 问题。
- 看响应时间:Statistics → TCP Stream Graph → Time-Sequence Graph,能直观看到吞吐变化和拥塞窗口变化。
如果传输内容涉及 HTTPS,抓包看到的是加密数据,没法直接看到 HTTP 头部,但 TCP 层的握手、重传、窗口等信息依然可见。要分析应用层内容,可以在支持的环境下配置 SSLKEYLOGFILE 环境变量配合 Wireshark 解密,不过生产环境操作需评估安全合规,这里就不展开。
6. 数据通信过程常见疑问的个人看法
6.1 为什么抓包看到的序列号是从 0 开始的
很多第一次抓包的朋友都会疑惑:TCP 初始序列号明明是随机大数,为什么抓包显示 Seq=0?因为 Wireshark 默认开启了“相对序列号”显示,把第一次握手时的绝对序列号归一化为 0,方便人看。想确认真实的随机初始序列号,可以在 Wireshark 里右键 TCP 层,Protocol Preferences,取消勾选“Relative sequence numbers”,再重新看。这个细节不影响排错,但会影响对协议的理解,建议还是知道一下。
6.2 TCP 的可靠性与 UDP 的“裸奔”
前面大篇幅讲的都是 TCP,因为它是理解数据通信过程的绝佳模型。但互联网上大量实时流量用的是 UDP——DNS、视频通话、游戏同步包、QUIC/HTTP3 都跑在 UDP 上。UDP 没有握手,没有确认,应用发了就发,丢了就丢。
为什么?“可靠”是有代价的。TCP 的确认、重传、窗口管理,带来了额外的往返时间和头部开销。对实时音视频来说,旧数据晚到了不如不到,用 TCP 反而会因重传导致更大延迟。所以通信过程的设计不是越可靠越好,而是“合适的可靠性匹配合适的场景”。理解这一点,才会明白为什么 QUIC 要在 UDP 上重新实现一套自己的可靠性机制——因为它想既保留 TCP 的可靠性,又减少握手延退,同时避免中间设备对 TCP 的干扰。
6.3 数据通信过程理解得越深,排错定位越快
最后说点实在的。做了这么多年的网络和运维,我越来越觉得,“理解数据通信过程”本质上就是建立一张心智地图:数据从哪来、现在在哪一层、下一站去哪、每一站做了什么决策。有了这张地图,所有的排查工具(ping、traceroute、抓包、查路由表、看 ARP)都是辅助你在地图上定位的探针,而不是什么神秘的魔法。
很多新人遇到问题喜欢一个命令一个命令地试运气,这样效率极低。真正高效的做法是:先在脑海里走一遍完整的数据通信过程,逐个环节排除。比如 A 访问 B 不通,先走 OSI:物理层通不通(link 亮不亮)→ 链路层通不通(ARP 能不能解析)→ 网络层通不通(IP 路由能不能到)→ 传输层通不通(端口监听和防火墙)→ 应用层通不通(服务进程是否正常)。每一层都有对应的验证方法,逐层向上,问题范围越缩越小,最终落到某一层上。
这个习惯养成之后,你会发现绝大多数网络故障都变成了一种“穷举加排除”的确定性工作,而不是靠玄学。今天的通信过程拆解就到这里,下次你再遇到网络不通,别急着甩锅给“网络不稳定”,先把这六层过一遍,绝大多数问题都能找到明确答案。