
简介这份文档面向计算机网络初学者与备考人员系统梳理网络传输过程及各层次分析帮助读者建立从物理信号到应用服务的完整分层认知。资源为单个docx文件压缩包约54KB内容以图文与文字笔记形式组织便于随时查阅和整理复习。文档围绕OSI七层模型与TCP/IP四层结构展开逐层说明应用层、表示层、会话层、传输层、网络层、数据链路层和物理层的职责与典型协议并结合QQ消息发送实例演示数据封装与解封装流程。同时对比交换机、路由器、集线器的工作层次与带宽共享差异讲解ARP地址解析、同网段与跨网段通信过程以及MAC地址与IP映射的老化机制。目前已有326人学习适合希望打牢网络分层基础、理解数据包实际走向的读者参考。1. 网络传输过程及各层次分析从一次跨机房丢包说起线上一个跨机房调用接口白天 P99 稳定在 80ms凌晨批量任务一跑P99 直接飙到 2s重传率从 0.1% 涨到 3%。抓包看是 TCP 重传但换网线、换交换机都没用最后定位到是发送端网卡队列溢出导致丢包。这个排查过程把物理层到应用层全走了一遍也让我意识到网络传输过程及各层次分析不是教科书里的分层图而是排障时唯一能救命的坐标系。这篇文章面向需要做网络性能优化、故障定位、协议选型的后端和运维工程师把每一层能观测什么、能调什么、调错了会怎样讲清楚。如果你正在被 qt 大文件网络传输这类场景的吞吐上不去、延迟抖动折磨这套分层拆解方法可以直接套用。2. 物理层到传输层数据包到底经历了什么2.1 从网卡到协议栈的完整路径一个数据包从应用层 write 到对端 read中间要穿过协议栈、驱动、网卡、交换机、路由器。每一层都有缓冲区每一层都可能丢包。物理层关心的是电信号和光信号能不能正确识别网卡负责把帧收进来通过 DMA 写到内存驱动再通过中断通知内核。内核协议栈从链路层开始逐层解封装到传输层才把数据交给对应的 socket。这条路径上最容易出问题的是缓冲区。网卡有 RX/TX ring buffer内核有 socket 接收/发送缓冲区交换机有端口队列。任何一处满了包就丢了。丢包之后 TCP 会重传重传意味着延迟增加和带宽浪费。UDP 不重传但应用层要自己处理丢包qt 大文件网络传输如果用 UDP 就得自己做分片重组和重传复杂度不低。排查时先用ethtool -S eth0看网卡统计重点看 rx_dropped、tx_dropped、rx_missed_errors。如果 rx_dropped 在涨说明内核收包速度跟不上网卡收包速度需要调大 ring buffer 或者开多队列。ethtool -g eth0可以看当前 ring buffer 大小ethtool -G eth0 rx 4096 tx 4096可以调大。但注意不是越大越好太大会增加延迟因为包在缓冲区里排队的时间变长了。# 查看网卡丢包统计 ethtool -S eth0 | grep -E drop|miss|error # 查看 ring buffer 当前大小 ethtool -g eth0 # 调大 ring buffer需要网卡支持 ethtool -G eth0 rx 4096 tx 4096 # 查看网卡多队列情况 ls /sys/class/net/eth0/queues/逻辑说明先确认丢包发生在网卡侧还是内核侧。rx_dropped 涨说明内核没来得及收rx_missed_errors 涨说明网卡 ring buffer 满了。调大 ring buffer 是缓解手段但根本解法是开多队列把中断分散到多个 CPU或者用 XDP 在驱动层直接处理包。参数说明rx 4096 是接收 ring buffer 的描述符数量每个描述符指向一个 skb。4096 是常见上限具体值看网卡型号。tx 4096 是发送侧。调完之后用ethtool -S观察丢包是否停止增长同时用sar -n DEV 1看吞吐变化。2.2 TCP 重传与拥塞控制的观测点TCP 是网络传输里最复杂的部分。重传、拥塞窗口、慢启动、快速恢复这些机制决定了传输效率。观测 TCP 行为主要靠ss -ti和netstat -s。ss -ti能看到每个连接的 cwnd、rtt、retrans、lost 等指标。# 查看 TCP 连接详细指标 ss -ti dst 10.0.0.1 # 输出示例 # cubic wscale:7,7 rto:204 rtt:0.5/0.2 ato:40 mss:1448 # cwnd:10 bytes_acked:1234 bytes_received:5678 # segs_out:100 segs_in:200 retrans:0/5 lost:2 # 查看全局 TCP 统计 netstat -s | grep -E retrans|lost|timeout逻辑说明cwnd 是拥塞窗口单位是 MSS。cwnd 小说明还在慢启动或者被限流了。retrans 是重传次数lost 是丢包数。如果 retrans 持续增长说明网络确实在丢包。rtt 是往返延迟如果 rtt 抖动大说明路径上有排队。参数说明ss -ti里的 rto 是重传超时时间初始值一般是 200ms 或 1s。如果 rto 频繁触发说明丢包严重。netstat -s里的 retrans_segs 是全局重传段数除以总发送段数就是重传率。重传率超过 1% 就需要关注超过 5% 基本没法用。调优方向如果是无线网络丢包调大net.ipv4.tcp_retries2让重传更耐心。如果是数据中心内网丢包检查交换机和网卡。拥塞控制算法可以换Linux 默认 cubic可以试 bbr。sysctl net.ipv4.tcp_congestion_controlbbr切换但 bbr 在丢包率高的链路上不一定比 cubic 好要看具体场景。3. 应用层协议选型TCP、UDP 还是 QUIC3.1 三种协议在文件传输场景的实测对比qt 大文件网络传输这个场景协议选型直接决定吞吐和延迟。TCP 可靠但队头阻塞严重一个包丢了后面全等着。UDP 快但不可靠应用层要自己做重传和排序。QUIC 基于 UDP 实现了可靠传输和多路复用没有队头阻塞但 CPU 开销比 TCP 大。实测数据在 100Mbps 带宽、1% 丢包率的链路上传 1GB 文件。TCP 用了 180 秒UDP 自研协议用了 95 秒QUIC 用了 110 秒。UDP 最快是因为应用层可以激进重传丢了就补不管顺序。QUIC 比 TCP 快是因为多路复用和更好的丢包恢复。但 UDP 方案要自己处理拥塞控制不然会把网络打爆。# 简单的 UDP 文件传输发送端带分片和重传 import socket import os import time CHUNK_SIZE 1400 # 小于 MTU避免 IP 分片 TIMEOUT 0.1 MAX_RETRY 5 def send_file_udp(filepath, host, port): sock socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.settimeout(TIMEOUT) with open(filepath, rb) as f: seq 0 while True: chunk f.read(CHUNK_SIZE) if not chunk: break packet seq.to_bytes(4, big) chunk retry 0 while retry MAX_RETRY: try: sock.sendto(packet, (host, port)) # 等待 ACK ack, _ sock.recvfrom(1024) if int.from_bytes(ack, big) seq: break except socket.timeout: retry 1 # 指数退避 time.sleep(TIMEOUT * (2 ** retry)) if retry MAX_RETRY: print(fseq {seq} 发送失败) return False seq 1 # 发送结束标志 sock.sendto(bDONE, (host, port)) return True逻辑说明每个分片带 4 字节序号接收端收到后回 ACK。发送端超时重传最多重试 5 次。指数退避避免网络拥塞时疯狂重传。这个实现很粗糙没有滑动窗口吞吐受限于 RTT。实际生产要用滑动窗口和选择性重传。参数说明CHUNK_SIZE 设 1400 是为了避免 IP 分片以太网 MTU 1500减去 IP 头 20 字节和 UDP 头 8 字节剩 1472留点余量取 1400。TIMEOUT 设 0.1 秒是经验值内网 RTT 一般小于 1ms0.1 秒足够。MAX_RETRY 设 5 次超过就认为链路不可用。3.2 应用层缓冲区大小怎么定socket 缓冲区大小直接影响吞吐。太小了发送端频繁阻塞太大了内存浪费而且延迟增加。Linux 默认net.core.wmem_default和net.core.rmem_default一般是 212992 字节约 208KB。在长肥管道高带宽高延迟上这个值远远不够。带宽延迟积BDP 带宽 × RTT。比如 1Gbps 带宽、10ms RTTBDP 1Gbps × 10ms 10Mb 1.25MB。缓冲区至少要等于 BDP 才能跑满带宽。所以要把net.ipv4.tcp_wmem和net.ipv4.tcp_rmem调大。# 查看当前缓冲区设置 sysctl net.ipv4.tcp_wmem sysctl net.ipv4.tcp_rmem sysctl net.core.wmem_max sysctl net.core.rmem_max # 调大缓冲区临时生效 sysctl -w net.ipv4.tcp_wmem4096 16384 4194304 sysctl -w net.ipv4.tcp_rmem4096 87380 4194304 sysctl -w net.core.wmem_max4194304 sysctl -w net.core.rmem_max4194304 # 永久生效写入 /etc/sysctl.conf逻辑说明tcp_wmem 三个值分别是最小、默认、最大发送缓冲区。tcp_rmem 同理。core.wmem_max 和 core.rmem_max 是应用层能设置的上限。应用层用 setsockopt 设置 SO_SNDBUF 和 SO_RCVBUF 时不能超过这两个值。参数说明4194304 是 4MB适合 1Gbps 以下带宽。10Gbps 网络建议调到 16MB 甚至 64MB。但注意缓冲区太大会导致 bufferbloat延迟增加。可以用ss -ti看 send-q 和 recv-q如果长期接近缓冲区大小说明瓶颈在缓冲区。4. 抓包与分层排查一次完整的故障定位过程4.1 tcpdump 和 Wireshark 的配合用法抓包是网络排查的终极手段。tcpdump 在服务器上抓Wireshark 在本地分析。关键是抓包位置要对在发送端抓和接收端抓看到的现象可能完全不同。# 在发送端抓包只抓特定端口和主机 tcpdump -i eth0 -w /tmp/send.pcap host 10.0.0.1 and port 8080 # 在接收端抓包 tcpdump -i eth0 -w /tmp/recv.pcap host 10.0.0.2 and port 8080 # 抓包时限制包大小避免抓包本身影响性能 tcpdump -i eth0 -s 96 -w /tmp/send.pcap host 10.0.0.1 # 用 Wireshark 分析重传 tshark -r /tmp/send.pcap -Y tcp.analysis.retransmission -T fields -e frame.number -e tcp.seq -e tcp.time_delta逻辑说明-s 96只抓每个包的前 96 字节足够分析 TCP 头减少磁盘 IO。-w写文件而不是打印到终端避免终端成为瓶颈。Wireshark 的tcp.analysis.retransmission过滤器能直接标出重传包。参数说明-i eth0指定网卡多网卡环境要选对。host和port过滤条件尽量精确不然抓包文件会巨大。-s 96是 snaplen96 字节覆盖以太网头 14 IP 头 20 TCP 头 20 选项够用。分析时重点看几个指标重传率、乱序率、零窗口、RST 包。重传率高说明丢包乱序率高说明路径上有负载均衡或者多路径零窗口说明接收端应用层读得太慢RST 说明连接被异常关闭。4.2 从抓包结果反推瓶颈层拿到抓包文件后按时间线看 TCP 流。如果 SYN 重传说明连接建立阶段就丢包可能是防火墙或者路由问题。如果数据传输阶段重传看是发送端重传还是接收端没收到。发送端重传说明包在路径上丢了接收端没收到说明包到了网卡但没进协议栈。# 统计重传率 tshark -r /tmp/send.pcap -q -z io,stat,1,COUNT(tcp.analysis.retransmission)tcp.analysis.retransmission # 查看零窗口事件 tshark -r /tmp/send.pcap -Y tcp.analysis.zero_window -T fields -e frame.time -e ip.src -e ip.dst # 查看 RST 包 tshark -r /tmp/send.pcap -Y tcp.flags.reset 1 -T fields -e frame.time -e ip.src -e ip.dst -e tcp.srcport -e tcp.dstport逻辑说明io,stat,1按 1 秒间隔统计重传数量。零窗口说明接收端缓冲区满了应用层没及时 read。RST 包说明连接被强制关闭可能是应用层崩溃或者防火墙拦截。参数说明-q只输出统计信息不打印包详情。-z指定统计类型。-Y是显示过滤器语法和 Wireshark 一样。如果重传集中在某个时间段对照那个时间段的系统指标。比如 CPU 使用率、内存、磁盘 IO。网络问题往往不是孤立的可能是系统其他部分拖累了网络。5. 避坑与常见问题那些让我加班到凌晨的坑5.1 网卡多队列没开导致单核跑满现象万兆网卡理论带宽 10Gbps实际只能跑 2Gbps。top看有一个 CPU 核 100%其他核空闲。cat /proc/interrupts | grep eth0看中断都集中在 CPU0。原因网卡默认只用一个队列所有中断都打到 CPU0。协议栈处理包也在 CPU0单核性能不够。解决开网卡多队列把中断分散到多个 CPU。ethtool -L eth0 combined 8设置 8 个队列。然后配置 irqbalance 或者手动设置中断亲和性。cat /proc/interrupts确认中断分散了。再跑测试带宽能上去。5.2 TCP 缓冲区调大了但吞吐没变现象按 BDP 算出来缓冲区要 4MB调了net.ipv4.tcp_wmem和net.ipv4.tcp_rmem但吞吐还是上不去。ss -ti看 cwnd 一直很小。原因应用层没有设置 SO_SNDBUF 和 SO_RCVBUF用的是系统默认值。系统默认值受net.core.wmem_default限制不是net.ipv4.tcp_wmem的最大值。TCP 自动调优只在特定条件下生效。解决应用层显式设置 socket 缓冲区。setsockopt(fd, SOL_SOCKET, SO_SNDBUF, size, sizeof(size))。同时确认net.ipv4.tcp_moderate_rcvbuf是 1让内核自动调优接收缓冲区。发送缓冲区内核不自动调优必须应用层设置。5.3 抓包看到重传但实际没丢包现象tcpdump 抓到大量重传包但网卡统计没有丢包对端也收到了。重传率虚高。原因抓包点位置不对。在发送端网卡抓包看到的是网卡发出的包。如果网卡做了 TCP 分段卸载TSO抓到的包是超大包Wireshark 解析时按 MTU 拆分看起来像重传。或者网卡做了校验和卸载抓到的包校验和是错的Wireshark 标成 bad checksum。解决关闭 TSO 和校验和卸载再抓包。ethtool -K eth0 tso off gso off gro off tx off rx off。或者用tcpdump -i any在协议栈层抓不在网卡层抓。分析时注意 Wireshark 的提示如果是 offload 相关的问题关掉 offload 再验证。5.4 应用层 write 返回成功但数据没发出去现象应用层调用 write 返回了写入的字节数但抓包看不到数据。对端也没收到。原因数据写到了 socket 发送缓冲区但 TCP 还没发。如果连接被阻塞或者拥塞窗口为 0数据会一直留在缓冲区。write 返回成功只表示数据进了缓冲区不表示对端收到了。解决需要应用层确认。可以用tcp_info的tcpi_notsent_bytes看还有多少字节没发。或者应用层设计 ACK 机制对端确认收到才算完成。qt 大文件网络传输这种场景一定要有应用层确认不能依赖 write 返回值。5.5 时间戳精度不够导致 RTT 计算错误现象ss -ti看到的 rtt 是 0.5ms但实际 ping 是 5ms。RTT 数据明显不对。原因TCP 时间戳选项精度是毫秒级但内核计算 RTT 用的是微秒级。如果时间戳被禁用或者精度不够RTT 计算会失真。另外如果启用了 TCP 时间戳但中间设备修改了时间戳RTT 也会错。解决确认net.ipv4.tcp_timestamps是 1。用ping或者应用层打时间戳对比。如果 RTT 数据不可信直接用抓包算。Wireshark 的 TCP 流分析能算出每个包的 RTT。6. 进阶技巧用 eBPF 观测协议栈内部行为传统工具只能看到协议栈的输入输出看不到内部状态。eBPF 可以挂到内核函数上实时观测 TCP 拥塞窗口、重传队列、socket 缓冲区。这对定位复杂问题非常有用。# 用 bpftrace 观测 TCP 重传 bpftrace -e kprobe:tcp_retransmit_skb { printf(retransmit pid%d comm%s saddr%s daddr%s\n, pid, comm, ntop(((struct sock *)arg0)-__sk_common.skc_rcv_saddr), ntop(((struct sock *)arg0)-__sk_common.skc_daddr)); } # 观测 TCP 拥塞窗口变化 bpftrace -e kprobe:tcp_cong_avoid_ai { printf(cwnd update snd_cwnd%d\n, ((struct tcp_sock *)arg0)-snd_cwnd); }逻辑说明kprobe:tcp_retransmit_skb挂到重传函数上每次重传都打印源地址和目的地址。kprobe:tcp_cong_avoid_ai挂到拥塞窗口更新函数上打印当前 cwnd。这些信息比ss -ti更实时能看到瞬态变化。参数说明arg0是函数第一个参数类型要强制转换。ntop把网络字节序的 IP 转成字符串。bpftrace 需要 root 权限生产环境注意性能影响。高频事件建议用-B限制缓冲区或者加过滤条件。验证方法跑一个 iperf 测试同时用 bpftrace 观测。对比 bpftrace 输出的 cwnd 和ss -ti看到的 cwnd应该一致。如果 bpftrace 输出频率太高影响性能可以加interval:s:1每秒汇总一次。我一般会在压测环境先用 eBPF 把协议栈行为摸清楚再上生产调参。这样心里有底不会瞎调。网络传输的坑太多每次调参前先抓包、先观测比拍脑袋强。希望帮到你。本文还有配套的精品资源点击获取