
简介这份PPT课件面向计算机专业学生及网络协议自学者系统梳理计算机网络自顶向下方法中运输层的核心知识帮助读者从应用层需求出发理解端到端通信机制。内容围绕运输层服务展开涵盖多路复用与多路分解、UDP无连接传输、可靠数据传输原理、TCP连接与报文段结构、流量控制、拥塞控制原则及TCP拥塞控制机制等模块并配有rdt1至rdt3、回退N帧、选择重传等协议演进脉络便于对照学习协议设计思路。资源包共1个文件为ppt格式大小约1.82MB结构紧凑适合课堂讲授、期末复习或考研备考时快速查阅。目前已有58人学习可作为运输层章节的配套讲义帮助读者建立从服务模型到具体协议实现的完整认知框架。1. 从一份“计算机网络自顶向下.ppt”里我到底该学到什么很多人手里都有一份“计算机网络自顶向下.ppt”可能是老师发的课件也可能是从各种渠道攒来的复习资料。打开一看前几页讲互联网边缘、接入网翻到中间突然跳到运输层TCP 三次握手、UDP 协议栈、拥塞控制全堆在一起最后几页又变成网络安全和 HTTP。信息量很大但真正动手抓一次包、写一段 socket、调一次 iperf3 打流的时候才发现 PPT 上的箭头和状态机根本对不上真实网络里的行为。这份材料真正的价值不在于把每一页背下来应付期末而在于它提供了一条“自顶向下”的路径从应用层你每天用的 HTTP、DNS 出发往下追到运输层的 TCP/UDP再落到网络层的 IP 和链路层。对一线工程师来说这条路径能帮你把“为什么浏览器卡住”“为什么 UDP 打流丢包”“为什么 TCP 连接被 reset”这些现象一层层定位到具体协议行为上。它适合正在准备计算机网络期末复习的学生也适合需要补网络基础的后端、嵌入式、运维从业者。接下来我不复述 PPT而是按这条路径把运输层最核心的 TCP、UDP、拥塞控制拆成能复现、能验证、能排错的实操笔记。2. 运输层两大件TCP 和 UDP 到底怎么选、怎么抓2.1 从“我们的系统检测到您的计算机网络中存在异常流量”说起热搜里反复出现“我们的系统检测到您的计算机网络中存在异常流量。请稍后重新发送请求。为什么会这”这个提示背后往往不是玄学而是运输层行为触发了中间设备的限速或拦截。要理解它先得把 TCP 和 UDP 的差异落到报文上而不是停留在“TCP 可靠、UDP 快”这种口诀。TCP 是面向连接的通信前要三次握手通信中有序号、确认号、窗口字段结束时四次挥手。UDP 无连接头部只有 8 字节源端口、目的端口、长度、校验和发出去就不管了。PPT 里通常用一张对比表带过但真正排错时你需要看到的是TCP 的每一个行为都对应头部字段的变化UDP 的每一次“不可靠”都对应应用层要自己补的机制。我一般会先抓一段真实流量把 PPT 上的字段和 Wireshark 里的列一一对上。下面这条命令在 Linux 上抓本机 80 端口的 TCP 流量保存成 pcap 供后续分析。# 抓取 eth0 上 80 端口的 TCP 报文-s 0 表示抓完整包-w 写入文件 sudo tcpdump -i eth0 -s 0 -w tcp80.pcap tcp port 80 # 抓取 UDP 53 端口DNS的报文对比两者头部差异 sudo tcpdump -i eth0 -s 0 -w udp53.pcap udp port 53逻辑说明-i eth0指定网卡实际环境可能是ens33、wlan0用ip addr确认。-s 0抓完整帧否则默认只抓 96 字节看不到应用层数据。-w把原始包写文件避免终端刷屏。抓完后用 Wireshark 打开展开 TCP 头部重点看 Sequence Number、Acknowledgment Number、Flags、Window Size 这四个字段。UDP 头部则只有四个字段对比之下就能明白为什么 UDP 没有重传和流控。参数上tcp port 80是 BPF 过滤表达式可以换成host 10.0.0.5 and tcp只抓某台主机。如果只想看握手过程加-c 20抓 20 个包就停。注意在生产机器上抓包要控制文件大小-C 10 -W 5可以循环写 5 个 10MB 文件避免打满磁盘。2.2 用 Python 写最小 TCP/UDP 回显亲手验证三次握手和丢包光看 PPT 记不住写一遍最小代码就清楚了。TCP 服务端调用listen之后客户端connect触发三次握手内核协议栈自动完成应用层感知不到。UDP 则没有握手sendto直接发。下面这段 Python 同时起 TCP 和 UDP 回显方便对比。import socket import threading def tcp_server(): s socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # 避免 TIME_WAIT 导致端口占用 s.bind((127.0.0.1, 9000)) s.listen(5) # 半连接队列长度对应三次握手未完成队列 while True: conn, addr s.accept() # 返回时三次握手已完成 data conn.recv(1024) conn.sendall(bTCP echo: data) conn.close() def udp_server(): s socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.bind((127.0.0.1, 9001)) while True: data, addr s.recvfrom(1024) # 无连接直接收 s.sendto(bUDP echo: data, addr) threading.Thread(targettcp_server, daemonTrue).start() threading.Thread(targetudp_server, daemonTrue).start() input(servers running, press enter to quit\n)逻辑说明TCP 的listen(5)参数是 backlog控制已完成三次握手但还没被accept取走的连接数不是未完成握手队列这点 PPT 经常写错。SO_REUSEADDR让服务端重启时不被 TIME_WAIT 卡住。UDP 的recvfrom每次都能拿到对端地址因为无连接服务端不维护状态。参数上recv(1024)的 1024 是单次最多读的字节数TCP 是字节流可能一次读不满生产代码要循环读。UDP 是数据报一次recvfrom对应一个完整报文缓冲区小于报文长度会截断多余部分丢弃。测试时用nc 127.0.0.1 9000发 TCP用echo -n hello | nc -u 127.0.0.1 9001发 UDP观察返回差异。2.3 用 iperf3 打流看 TCP 和 UDP 在真实链路上的表现热搜里“iperf3使用udp打流”是高频操作。TCP 模式下 iperf3 会自动做拥塞控制UDP 模式则要手动指定带宽否则默认 1Mbps 跑不出真实能力。下面两条命令分别测 TCP 和 UDP 吞吐。# 服务端 iperf3 -s # TCP 客户端测 10 秒每 1 秒报告一次 iperf3 -c 192.168.1.100 -t 10 -i 1 # UDP 客户端目标带宽 100Mbps测 10 秒 iperf3 -c 192.168.1.100 -u -b 100M -t 10 -i 1逻辑说明TCP 模式的结果里 Retr 列是重传次数Cwnd 列是拥塞窗口这两个值直接反映链路质量和拥塞控制行为。UDP 模式的结果里 Jitter 是抖动Lost/Total 是丢包率因为 UDP 不重传丢包只能靠应用层统计。参数上-b 100M是 UDP 目标带宽设太大直接丢包设太小测不出瓶颈一般从链路带宽的 80% 开始试。-t 10测 10 秒-i 1每秒输出一次。如果 UDP 丢包率超过 5%先查链路 MTU 和分片热搜里“udp划分ip数据报片”说的就是这件事UDP 报文超过 MTU 会被 IP 层分片任一分片丢失整个报文就废了所以大 UDP 包在公网上很脆弱。TCP 则通过 MSS 协商避免分片这是两者在真实网络里表现差异巨大的关键原因。3. TCP 三次握手、四次挥手抓包看状态写代码踩坑3.1 三次握手在 Wireshark 里长什么样PPT 上三次握手画三条箭头实际抓包看到的是 SYN、SYN-ACK、ACK 三个包每个包头部字段都值得盯。客户端发 SYNSequence Number 是随机初始序号Flags 里 SYN 置 1。服务端回 SYN-ACKAcknowledgment Number 是客户端序号加一自己的 Sequence Number 也是随机初始序号。客户端再发 ACK确认号是服务端序号加一此后进入 ESTABLISHED。用 2.2 的 TCP 服务端配合tcpdump抓一次过滤tcp port 9000就能看到完整过程。重点看两个随机初始序号它们不是从 0 开始这是为了防止旧连接的报文干扰新连接。热搜里“consider the subsequent tcp syn packet sent by your host. does the destinati”这类题考的就是 SYN 包的目的端口和标志位。三次握手的核心目的是双方交换初始序号并确认对方收发能力。两次不够因为服务端无法确认客户端能收到自己的 SYN-ACK四次多余因为 ACK 可以搭在 SYN-ACK 上。这个“为什么是三次”在期末复习里是必考在排错里对应的是半连接队列溢出服务端收到 SYN 后把连接放入半连接队列收到 ACK 才移入全连接队列队列满了新 SYN 就被丢弃表现为客户端连不上但服务端没日志。3.2 四次挥手和 TIME_WAIT为什么主动关闭方要等 2MSL四次挥手比握手多一次因为 TCP 是全双工每个方向要单独关闭。主动关闭方发 FIN对方回 ACK此时主动方进入 FIN_WAIT_2对方还能继续发数据。对方数据发完发 FIN主动方回 ACK然后进入 TIME_WAIT等 2MSL 才真正关闭。TIME_WAIT 的作用有两个一是保证最后一个 ACK 能到达对方如果丢了对方会重发 FIN主动方还能再回 ACK二是让本次连接的旧报文在网络中消散避免干扰使用相同四元组的新连接。热搜里“fins tcp c代码”和“tcp三次握手四次挥手”经常一起出现写 C 网络代码时如果主动关闭后立刻重启绑定同一端口就会遇到Address already in use这就是 TIME_WAIT 在起作用。解决方式是用SO_REUSEADDR它允许绑定处于 TIME_WAIT 的端口但不允许两个活跃 socket 绑同一端口。服务端还应该用SO_REUSEPORT做多进程负载均衡这是 Linux 3.9 之后的能力。注意SO_REUSEADDR不是“后悔药”它只解决重启问题不解决连接泄漏如果大量连接卡在 TIME_WAIT要查是不是短连接太多考虑连接池或长连接。3.3 用 ss 和 netstat 看连接状态分布抓包看单个连接看全局状态分布用ss。下面命令按状态统计 TCP 连接数快速判断是否有异常。# 统计各状态连接数 ss -tan | awk NR1 {print $1} | sort | uniq -c | sort -rn # 只看 TIME_WAIT 且目的端口是 80 的连接 ss -tan state time-wait ( dport :80 ) # 查看监听队列溢出情况 ss -lnt逻辑说明ss -tan列出所有 TCP 连接awk取第一列状态sort | uniq -c计数。state time-wait是 ss 的过滤语法比 grep 更准。ss -lnt的 Send-Q 列在 LISTEN 状态下表示全连接队列最大长度Recv-Q 表示当前已完成握手等待 accept 的连接数如果 Recv-Q 经常接近 Send-Q说明 accept 太慢要加工作线程或调大 backlog。参数上-t只看 TCP-a看所有-n不解析服务名-l只看监听。生产环境如果 TIME_WAIT 上万先确认是不是短连接风暴再考虑调net.ipv4.tcp_tw_reuse但这个参数只对主动发起连接的一方有效且依赖时间戳不要盲目开。4. 拥塞控制从 PPT 曲线到内核参数和真实调优4.1 慢启动、拥塞避免、快重传、快恢复到底在做什么PPT 上拥塞控制通常画一条 cwnd 随时间变化的曲线慢启动指数涨到阈值转拥塞避免线性涨丢包后要么超时回到慢启动要么收到三个重复 ACK 触发快重传和快恢复。这套机制的核心是发送方通过 ACK 的到达情况推断网络拥塞程度动态调整发送速率避免把网络压垮。慢启动的 cwnd 从 1 个 MSS 开始每收到一个 ACK 加 1 个 MSS实际效果是每 RTT 翻倍。ssthresh 初始很大第一次丢包后设为当前 cwnd 的一半然后 cwnd 降到 1 重新慢启动。快重传是收到三个重复 ACK 立刻重传丢失报文不等超时快恢复是把 cwnd 降到 ssthresh 而不是 1然后线性增长。这些行为在 Linux 内核里由拥塞控制算法实现默认是 CUBIC还有 BBR、Reno 等可选。热搜里“tcp流量控制和拥塞控制”经常混在一起考。流量控制是接收方通过窗口字段告诉发送方自己能收多少防止接收方被压垮拥塞控制是发送方根据网络反馈调整速率防止网络被压垮。两者一个端到端一个面向网络PPT 里通常用两个窗口区分接收窗口 rwnd 和拥塞窗口 cwnd实际发送窗口取两者最小值。4.2 查看和切换 Linux 拥塞控制算法Linux 下查看当前算法和可用算法# 查看当前拥塞控制算法 sysctl net.ipv4.tcp_congestion_control # 查看所有可用算法 sysctl net.ipv4.tcp_available_congestion_control # 临时切换为 BBR sudo sysctl -w net.ipv4.tcp_congestion_controlbbr # 查看 BBR 是否启用 sysctl net.ipv4.tcp_congestion_control逻辑说明tcp_congestion_control是全局默认算法新连接继承。tcp_available_congestion_control列出内核编译进去的模块如果没有 bbr 需要加载tcp_bbr模块。切换后只影响新连接已有连接不变。参数上CUBIC 适合大多数场景BBR 在有一定丢包的链路上表现更好因为它不把丢包当拥塞信号而是估计带宽和 RTT。但 BBR 在浅缓冲区设备上可能不公平抢占 CUBIC 连接的带宽。生产环境切换前要在测试链路验证不要直接上核心业务。另外net.ipv4.tcp_window_scaling要开启否则窗口最大 64KB高带宽高延迟链路跑不满。4.3 用 tc 模拟丢包和延迟验证拥塞控制行为想亲眼看到拥塞控制曲线可以用tc在本地网卡上加延迟和丢包再用 iperf3 打流观察 cwnd 变化。# 在 eth0 上加 100ms 延迟和 1% 丢包 sudo tc qdisc add dev eth0 root netem delay 100ms loss 1% # 查看规则 tc qdisc show dev eth0 # 测试完删除规则 sudo tc qdisc del dev eth0 root逻辑说明netem是网络模拟模块delay 100ms给每个包加 100ms 延迟loss 1%随机丢 1% 的包。配合 iperf3 TCP 模式能看到吞吐明显下降且重传增加。如果换成 BBR同样条件下吞吐可能更稳因为 BBR 不因少量丢包大幅降窗。参数上delay可以带抖动如delay 100ms 10msloss可以设相关性如loss 1% 25%。注意tc规则加在出口方向抓包时在另一台机器抓才看得到效果。测试完务必删除规则否则影响正常通信。这个手法在验证“tcp流量控制和拥塞控制”实验时非常直观比看 PPT 曲线有用得多。5. 避坑与排查运输层实操里最容易翻车的五件事5.1 现象UDP 打流丢包严重但带宽没跑满原因UDP 报文超过路径 MTU 被 IP 分片任一分片丢失整个报文丢弃或者发送速率超过链路能力中间设备直接丢。热搜里“udp划分ip数据报片”和“read udp: unknown error (code10054)”都指向这类问题后者在 Windows 上通常是对方端口不可达ICMP 端口不可达报文被返回表现为连接被重置。解决先用ping -M do -s 1472探测路径 MTU1472 加 28 字节 IP/ICMP 头等于 1500。UDP 应用层控制报文在 1400 字节以内避免分片。iperf3 UDP 模式从低带宽逐步加找到丢包拐点。Windows 上收到 10054 要检查对端是否真的在监听以及防火墙是否返回了 ICMP 不可达。5.2 现象TCP 连接偶尔连不上服务端没日志原因半连接队列或全连接队列溢出。服务端收到 SYN 后放入半连接队列收到 ACK 后移入全连接队列等待 accept。队列满时新 SYN 被丢弃客户端重试服务端内核可能没记录。解决ss -lnt看 Recv-Q 和 Send-QRecv-Q 接近 Send-Q 说明 accept 慢。调大net.core.somaxconn和net.ipv4.tcp_max_syn_backlog应用层listen的 backlog 也要调大。如果是 SYN 洪水开net.ipv4.tcp_syncookies但它只在半连接队列满时生效不能替代队列调优。5.3 现象服务重启报 Address already in use原因主动关闭方进入 TIME_WAIT端口还被占用。短连接服务频繁重启时必现。解决设置SO_REUSEADDR允许绑定 TIME_WAIT 端口。但注意如果之前有活跃连接绑同一端口仍然会失败。根本办法是减少短连接用连接池。不要用SO_REUSEPORT来绕过它语义不同是让多个 socket 绑同一端口做负载均衡。5.4 现象curl 报 tcp connection reset by peer原因对端在 TCP 连接建立后发送 RST常见于对端进程崩溃、端口未监听但被中间设备代答、或对端主动拒绝。热搜里“curl: (35) tcp connection reset by peer”和“error: listen tcp 127.0.0.1:11434: bind: only one usage of each socket addre”都是运输层典型报错后者是端口被占用前者是连接被重置。解决抓包看 RST 是谁发的。如果是服务端发的查服务端日志和dmesg。如果是中间设备查是否有负载均衡健康检查失败。bind: only one usage用ss -lntp找到占用进程杀掉或换端口。注意SO_REUSEADDR不能解决两个活跃进程绑同一端口。5.5 现象iperf3 TCP 吞吐远低于带宽原因窗口太小、拥塞控制算法保守、路径 RTT 大、或者有丢包。高带宽高延迟链路需要窗口缩放和足够的 cwnd。解决确认net.ipv4.tcp_window_scaling1net.core.rmem_max和wmem_max调大应用层设置SO_RCVBUF。用ss -tin看连接的 cwnd 和 rtt如果 cwnd 上不去查丢包和拥塞算法。BBR 在高延迟链路上通常比 CUBIC 好但要测试公平性。6. 把 PPT 变成实验手册一套可复用的自顶向下验证流程学完运输层最怕的是回到 PPT 又忘了。我的习惯是每学一个协议就写一个最小实验脚本抓一次包跑一次打流把结果和 PPT 对照。下面这套流程我反复用从应用层往下走每一层都有可验证的输出。第一步应用层。用curl -v访问一个 HTTP 站点看 DNS 解析、TCP 连接、TLS 握手、HTTP 请求响应的时间分布。curl -w可以格式化输出各阶段耗时定位是 DNS 慢还是 TCP 慢。curl -o /dev/null -s -w dns: %{time_namelookup} connect: %{time_connect} tls: %{time_appconnect} total: %{time_total}\n https://example.com第二步运输层。用tcpdump抓这次 curl 的包过滤tcp port 443在 Wireshark 里看三次握手、TLS 版本、四次挥手。重点确认 SYN 的 MSS 选项、窗口缩放选项、SACK 选项这些决定后续传输效率。第三步网络层。用traceroute看路径用ping -M do探测 MTU。如果路径中有 MTU 较小的跳TCP 会通过 MSS 协商避免分片UDP 则要应用层控制。第四步拥塞控制。用 iperf3 在同样路径打流对比 CUBIC 和 BBR 的吞吐和重传。用ss -tin观察 cwnd 变化和 PPT 曲线对照。第五步回归验证。把tc规则加上模拟丢包和延迟再跑一遍看哪些参数敏感。这套流程跑下来PPT 上的每个概念都有了对应的命令和输出期末复习和实际排错都能用。最后说一个我自己的教训早年调一个 UDP 服务丢包率一直下不来查了两天应用层代码最后发现是报文超过 MTU 被分片中间设备丢分片。从那以后任何 UDP 服务上线前我都先确认单包大小和路径 MTU这个习惯帮我省了很多后悔药。希望帮到你。本文还有配套的精品资源点击获取