☰
计算机网络基础知识实战:从抓包翻车到TCP/UDP排障与Wireshark技巧
2026/9/30 3:47:02 网站建设 项目流程

简介:这份PDF资料面向准备技术面试的IT求职者与网络初学者,系统梳理计算机网络核心考点,帮助读者在面试与工程实践中快速定位知识盲区。内容围绕OSI七层参考模型与TCP/IP四层模型展开,涵盖TCP/IP协议族、TCP/UDP/SCTP协议对比、三次握手与四次挥手、TCP状态机、TIME_WAIT状态、端口号、超时重传与快速重传、TCP Header结构、可靠传输、流量控制与拥塞控制,以及IPv4/IPv6、ICMP、ARP、RARP、IGMP等网络层协议,并附有OSI与TCP/IP模型区别等常见面试问题解析。资源包共1个PDF文件,大小约2.08MB,单文件结构便于通读与检索。目前已有969人学习,适合需要系统复习网络基础、对照面试题查漏补缺的读者,可作为面试冲刺与日常查阅的参考材料。

1. 计算机网络基础知识:从一次抓包翻车说起

很多人对「计算机网络基础知识」的印象停留在考试背题——OSI 七层、TCP 三次握手、UDP 无连接,背完就忘。但我真正意识到这些基础值钱,是因为一次线上事故:两台内网机器之间传文件,iperf3打流跑出来只有 2 Mbps,排查了半天以为是网线问题,最后抓包发现是 MTU 不匹配导致 IP 分片,大量分片在中间设备被丢弃。那一刻我才明白,OSI 七层模型和 TCP/IP 协议栈不是拿来考试的,是拿来定位问题的坐标系。

这篇笔记面向两类人:一是刚接触网络编程、想搞清数据从应用到网线到底经历了什么的新手;二是写过 socket 但遇到「能连上却传不动」「UDP 丢包不知道从哪查」这类问题、需要一套可复现排查路径的熟手。我会从分层模型讲到 TCP/UDP 的实操差异,再落到抓包、打流、参数调优的具体命令,每一步都能在你自己的机器上跑一遍。不聊虚的,只讲能复现的。

2. OSI 七层与 TCP/IP 四层:分层到底怎么帮你定位问题

2.1 两套模型不是对立的,是同一件事的粗细粒度

初学者最容易卡在「OSI 七层和 TCP/IP 四层到底学哪个」。结论很简单:排障时用 TCP/IP 四层做骨架,用 OSI 七层做细分。TCP/IP 模型是工程实现,OSI 是教学参考,两者对应关系如下。

OSI 七层TCP/IP 四层典型协议排障时看什么
应用层 / 表示层 / 会话层应用层HTTP、DNS、Modbus TCP业务日志、请求响应内容
传输层传输层TCP、UDP端口、连接状态、重传、丢包
网络层网络层IP、ICMP、IGMPIP 地址、路由、分片、TTL
数据链路层 / 物理层网络接口层Ethernet、ARP、Wi-FiMAC、网卡状态、CRC 错误

这张表的价值在于:当你拿到一个「网络不通」的问题,可以按层自下而上排除。先看网卡灯亮不亮(物理层),再看arp -a有没有对端 MAC(链路层),再ping通不通(网络层),再telnet ip port端口通不通(传输层),最后才看应用日志。这个顺序能帮你避免「一上来就怀疑代码」的常见误判。

2.2 数据在 TCP/IP 模型中的封装与解封装过程

理解封装是理解一切网络行为的前提。以你用浏览器发一个 HTTP 请求为例,数据往下走的每一步都会加一个头:

# 用 tcpdump 抓一个 HTTP 请求,直观看到每一层的头 sudo tcpdump -i eth0 -nn -vvv 'tcp port 80 and host 93.184.216.34' -c 5

抓到的包用 Wireshark 打开,你会看到从下到上依次是:Ethernet II(源/目的 MAC)→ IPv4(源/目的 IP、TTL、协议号)→ TCP(源/目的端口、序列号、标志位)→ HTTP(请求行、头部)。每一层只关心自己的头,不关心上层载荷,这就是分层的核心思想。

封装的关键参数有三个必须记住:

  • MTU(最大传输单元):以太网默认 1500 字节。IP 层如果发现上层数据超过 MTU,要么分片,要么通知 TCP 调整 MSS。分片是性能杀手,后面避坑章节会细讲。
  • MSS(最大报文段长度):TCP 握手时双方协商,通常 = MTU - IP 头(20) - TCP 头(20) = 1460。这是 TCP 不分片的保证。
  • TTL(生存时间):每经过一个路由器减 1,减到 0 丢弃并回 ICMP 超时。traceroute就是靠这个工作的。

2.3 用 ping 和 traceroute 验证网络层连通性

网络层排障的两个基本命令,很多人只会用不会读输出。

# 1. ping 指定源接口和包大小,验证 MTU 是否匹配 ping -I eth0 -s 1472 -M do 192.168.1.1 # -s 1472 表示数据部分 1472 字节,加上 ICMP 头 8 + IP 头 20 = 1500,正好等于 MTU # -M do 表示禁止分片,如果对端 MTU 小于 1500,这里会直接报错 # 2. traceroute 看路径,-n 不解析 DNS,-I 用 ICMP 探测 traceroute -n -I 8.8.8.8

ping -s 1472 -M do这个组合是排查 MTU 问题的黄金命令。如果小包能通、大包不通,基本可以锁定路径上某段 MTU 小于 1500。traceroute输出里如果某一跳之后全是*,说明那台设备不回应 ICMP,不一定是断了,可以换-T用 TCP 探测。

提示:Windows 下对应命令是ping -l 1472 -f,-f表示禁止分片;tracert替代traceroute。

3. TCP 与 UDP 的实操差异:三次握手、四次挥手与打流验证

3.1 TCP 三次握手不是背出来的,是抓出来的

「TCP 三次握手」被背烂了,但真正抓一次包,理解会完全不同。

# 在一台机器上监听,另一台机器连接,同时抓包 # 服务端(先启动) nc -l 9999 # 客户端 nc 192.168.1.100 9999 # 第三个终端抓包 sudo tcpdump -i any -nn 'tcp port 9999' -c 10

你会看到三个包:SYN→SYN+ACK→ACK。关键在序列号的变化:客户端发 SYN 时带一个随机初始序列号seq=x,服务端回 SYN+ACK 时带自己的seq=y并确认ack=x+1,客户端最后发 ACK 确认ack=y+1。三次握手的本质是双方各自确认对方的收发能力都正常,两次不够(服务端无法确认客户端能收到),四次多余。

四次挥手同理,因为 TCP 是全双工,每个方向要单独关闭,所以是FIN→ACK→FIN→ACK。主动关闭方最后会进入TIME_WAIT状态,等 2MSL(通常 60 秒)才释放。这个状态在高并发短连接场景下会耗尽端口,是后端常见的坑。

3.2 UDP 无连接不等于不可靠,关键看你怎么用

UDP 常被说成「不可靠」,但它的不可靠是指不保证到达、不保证顺序、不保证不重复,不是「不能用」。实时音视频、DNS、游戏同步、Modbus 广播都靠 UDP。用 UDP 的正确姿势是在应用层自己补机制。

# Python UDP 发送端:加序号和简单重传 import socket import struct import time sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.settimeout(0.5) # 设置超时用于重传判断 def send_with_retry(data, addr, seq, max_retry=3): # 包头加 4 字节序号,方便接收端去重和排序 packet = struct.pack('!I', seq) + data for i in range(max_retry): try: sock.sendto(packet, addr) ack, _ = sock.recvfrom(1024) # 等 ACK if ack == b'OK': return True except socket.timeout: print(f"seq={seq} 第 {i+1} 次超时,重传") return False for seq in range(10): ok = send_with_retry(f"payload-{seq}".encode(), ('192.168.1.100', 9999), seq) print(f"seq={seq} 发送{'成功' if ok else '失败'}")

这段代码演示了 UDP 上做可靠传输的最小骨架:序号用于去重和排序,超时重传用于保证到达,ACK 用于确认。参数上,settimeout(0.5)要根据你的网络 RTT 调整,局域网 0.1 秒够,跨公网可能要 1 秒以上。max_retry=3是经验值,再多说明链路本身有问题,重传也救不回来。

3.3 用 iperf3 分别打 TCP 和 UDP 流,看差异

iperf3是验证链路质量的标准工具,TCP 和 UDP 模式行为完全不同。

# 服务端 iperf3 -s # TCP 打流:默认就是 TCP,-t 时长,-P 并发数 iperf3 -c 192.168.1.100 -t 10 -P 4 # UDP 打流:-u 开启 UDP,-b 指定带宽,-l 指定包大小 iperf3 -c 192.168.1.100 -u -b 100M -l 1400 -t 10

TCP 模式下,iperf3会自动做拥塞控制,你看到的是实际能达到的吞吐,如果远低于链路带宽,说明有丢包或延迟。UDP 模式下,-b 100M是你强制发送的速率,iperf3会报告丢包率和抖动(jitter)。UDP 打流的意义在于测链路极限:逐步提高-b,直到丢包率超过 1%,那个点就是链路实际能承载的 UDP 吞吐。

-l 1400这个包大小有讲究:1400 + 8(UDP头) + 20(IP头) = 1428,小于 1500,避免分片。如果你设-l 1472,加上头正好 1500,某些设备可能因为额外封装(如 VLAN 标签)导致分片。

注意:UDP 打流会占满带宽,生产环境慎用,最好在维护窗口或独立测试链路做。

4. 避坑与排查:五个让我加班到凌晨的网络问题

4.1 现象:小包能 ping 通,大包全部超时

原因:路径上某段 MTU 小于 1500,通常是 PPPoE 拨号(MTU 1492)或隧道封装。大包被要求分片但设置了 DF 标志,直接被丢弃。

解决:用ping -s 1472 -M do逐步减小-s值,找到能通的最大值,那个值 + 28 就是实际 MTU。然后在应用层把发送缓冲区控制在 MTU 以内,或调整网卡 MTU:ip link set eth0 mtu 1400。

4.2 现象:TCP 连接建立成功,但传输大量数据时卡死

原因:典型的 MSS 协商问题。握手时双方协商的 MSS 是基于自己网卡的 MTU,但路径中间有更小 MTU 的设备,且 ICMP 被防火墙拦截,导致 PMTUD(路径 MTU 发现)失效。

解决:在服务端显式设置 MSS clamp:iptables -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu。或者直接在应用层限制单次发送大小。

4.3 现象:UDP 服务端recvfrom报Connection reset by peer或unknown error 10054

原因:Windows 下如果 UDP 发送方给一个未监听的端口发过包,对端会回 ICMP 端口不可达,Windows 把这个 ICMP 错误上报给了下一次recvfrom调用。这是 Windows 特有的行为,Linux 默认不报。

解决:用SIO_UDP_CONNRESET关闭这个行为:

// Windows 下关闭 UDP 连接重置上报 #include <winsock2.h> #include <mstcpip.h> BOOL bNewBehavior = FALSE; DWORD dwBytesReturned = 0; WSAIoctl(sock, SIO_UDP_CONNRESET, &bNewBehavior, sizeof(bNewBehavior), NULL, 0, &dwBytesReturned, NULL, NULL);

参数说明:SIO_UDP_CONNRESET是控制码,传入FALSE表示不接收 ICMP 重置错误。这段代码要在socket()之后、recvfrom()之前调用。

4.4 现象:iperf3UDP 打流丢包率极高,但 TCP 打流正常

原因:UDP 没有拥塞控制,你设的-b超过了链路实际承载能力,或者中间设备对 UDP 做了限速(很多企业网关会限制 UDP 带宽防止 P2P)。

解决:先用 TCP 打流测出实际带宽,UDP 的-b设为 TCP 结果的 80% 左右。如果 UDP 丢包但 TCP 正常,基本可以确认是中间设备限速,需要找网络管理员确认策略。

4.5 现象:服务端大量TIME_WAIT,新连接建不上

原因:短连接高并发场景,主动关闭方会进入TIME_WAIT等 2MSL,端口被占用。Linux 默认本地端口范围约 28000 个,如果 QPS 高,很快耗尽。

解决:三个方向——开启tcp_tw_reuse复用(sysctl -w net.ipv4.tcp_tw_reuse=1),让客户端主动关闭改为服务端被动关闭,或者改用长连接。注意tcp_tw_recycle在新内核已移除,不要再用。

提示:ss -s可以快速看当前连接状态统计,ss -tan state time-wait | wc -l看 TIME_WAIT 数量。

5. 进阶技巧:用 Wireshark 过滤器把排障时间砍一半

前面讲的都是命令行,但真正定位复杂问题,Wireshark 的显示过滤器是效率倍增器。我一般会先抓全量包,再用过滤器逐层缩小范围。

常用的过滤器组合,按排障场景分:

场景过滤器说明
看某个 TCP 流tcp.stream eq 5右键包 → Follow → TCP Stream 可拿到流号
看重传tcp.analysis.retransmission重传多说明链路丢包或拥塞
看零窗口tcp.analysis.zero_window接收方缓冲区满,发送方被暂停
看 UDP 丢包udp && !icmp结合序号看哪些序号缺失
看 IP 分片ip.flags.mf == 1 || ip.frag_offset > 0有分片说明 MTU 有问题
看 DNS 慢dns.time > 0.5响应超过 500ms 的 DNS 查询

我自己的习惯是:先看tcp.analysis.flags有没有异常标志,再看tcp.time_delta有没有大间隔。大间隔通常意味着应用层处理慢或网络抖动,比看吞吐更直观。

还有一个技巧是给抓包文件加时间戳标记。在关键操作前后用echo打时间点,抓包时用-w存文件,事后用frame.time过滤对齐:

# 抓包存文件,同时记录操作时间点 date +%s.%N > /tmp/mark.txt sudo tcpdump -i eth0 -w /tmp/capture.pcap 'host 192.168.1.100' # 复现问题后 Ctrl+C,用 Wireshark 打开,按 frame.time 排序

最后说一个我踩过的坑:不要在生产高峰期抓全量包。tcpdump默认缓冲区 2MB,高流量下会丢包,你抓到的包本身就不完整,分析结论全是错的。正确做法是用-B加大缓冲区(单位 KB),或者用-s 96只抓包头,减少数据量。

# 生产环境安全抓包:只抓包头,加大缓冲,限制包数 sudo tcpdump -i eth0 -s 96 -B 4096 -c 10000 -w /tmp/cap.pcap 'tcp port 8080'

-s 96表示每个包只截取前 96 字节,足够看到以太网头、IP 头、TCP 头,但看不到应用层载荷,适合分析连接和重传问题。-B 4096把缓冲区加到 4MB,-c 10000抓够一万个包自动停,避免磁盘写满。

这套方法我用了三年,从最初的「抓包看不懂」到现在「打开 Wireshark 五分钟定位」,核心就一句话:分层看,逐层过滤,先看异常标志再看时间间隔。网络基础知识的价值不在背,在于你遇到问题时脑子里有没有那张分层图。希望帮到你。

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

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

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

立即咨询