
简介本资源是《计算机网络》第七版配套课后习题完整参考答案面向高校计算机、网络工程及相关专业本科生与考研复习者用于巩固章节核心概念、检验学习效果并辅助理解典型计算题解法。答案覆盖第一章“概述”全部18道习题内容紧扣教材重点包括连通性与共享性服务本质、三种交换方式对比、因特网演进阶段与标准制定流程、internet/Internet区分、网络分类与性能指标计算如时延、时延带宽积、RTT等并提供详细推导过程与关键结论。资源为单个Word文档.doc格式体积精简仅150KB便于查阅与打印结构清晰、排版规范。目前已有1372人下载学习是备考期末考试、梳理知识脉络及攻克计算难点的实用型学习资料。1. 这不是“抄作业指南”而是网络协议理解的校验器用第七版课后答案反向锤炼 TCP/IP 实战直觉你手头那本《计算机网络第七版》翻到第 327 页看到 TCP 拥塞控制的四个算法——慢启动、拥塞避免、快重传、快恢复——是不是只记住了名字合上书Wireshark 抓包里突然冒出一串 RTO 重传和 Dup ACK你却没法把图上的 cwnd 曲线和屏幕上跳动的 Sequence Number 对上号这正是第七版课后答案最被低估的价值它不是标准答案集而是一套可执行的协议行为验证脚本集。谢希仁老师在第七版中大幅强化了 TCP 状态机建模、BGP 路径属性分析、HTTP/2 多路复用与流控机制等实战模块对应的习题答案里埋着大量可复现的时序图推演、有限状态机迁移表、以及 RFC 文档关键字段比对逻辑。我带学生做课程设计时常把第 5 章“运输层”全部 23 道计算题的答案拆成 Python 脚本用 scapy 构造不同 cwnd 场景下的 TCP 包序列再用 tcpdump 验证答案里写的“第 4 次 ACK 后进入快恢复”的判定条件是否真能被内核触发。适合正在啃 RFC 793 / 2581 / 6298 的人也适合刚配完 Cisco 路由器却对 BGP Local Preference 和 MED 的优先级打架感到困惑的工程师——这份答案集本质是把教科书里的协议规范翻译成你能亲手敲命令、看日志、改参数的调试手册。2. 从答案反推协议行为用第 5 章 TCP 计算题构建可验证的状态机模型2.1 第 5.23 题慢启动阈值 ssthresh 的动态跃迁逻辑必须落地为代码第七版第 5 章第 23 题要求计算某 TCP 连接在连续丢包后的 ssthresh 值变化。标准答案只给出最终数值但真正关键的是ssthresh 如何被内核实际更新。Linux 内核 5.10 中tcp_cong_control()函数在收到三个 Dup ACK 后调用tcp_fastretrans_alert()其中tcp_enter_recovery()会执行tp-snd_ssthresh max(tp-snd_cwnd/2, 2U)。但注意这个“除以 2”不是简单整除而是向下取整且不低于 2 MSS。我们用 Python scapy 构造一个最小验证环境from scapy.all import * import time def build_tcp_syn_ack_flow(): # 模拟初始三次握手设置 MSS1460 ip IP(dst127.0.0.1) syn TCP(dport80, flagsS, seq100, options[(MSS, 1460)]) syn_ack sr1(ip/syn, timeout1, verbose0) # 发送 10 个数据包每个 1460 字节触发慢启动 for i in range(10): data_pkt TCP(dport80, flagsPA, seq101i*1460, acksyn_ack[TCP].seq1) send(ip/data_pkt/bX*1460, verbose0) time.sleep(0.01) # 控制发送节奏 # 此时 cwnd 应为 10 * MSS 14600ssthresh 初始为 65535 print(Initial cwnd:, 10*1460, ssthresh:, 65535) build_tcp_syn_ack_flow()这段代码不追求真实连接而是强制构造出教材题干所需的初始窗口状态。关键点在于time.sleep(0.01)是为了确保 ACK 不堆积让内核按 RFC 5681 规则逐步增加 cwnd而options[(MSS, 1460)]直接锚定后续所有计算的字节基准——第七版所有 TCP 计算题默认 MSS1460若你用 Wireshark 抓包发现 MSS1380答案里的 cwnd 值就会系统性偏移。这就是为什么答案里第 23 题第二问强调“假设 MSS1460”它不是废话而是整个计算链的起点。2.2 第 5.27 题RTO 计算必须绑定到具体 RTT 样本序列第七版第 5.27 题给出 5 个 RTT 样本20ms, 30ms, 25ms, 40ms, 35ms要求计算平滑 RTTSRTT和 RTO。标准答案套用 Jacobson 公式SRTT ← α × SRTT (1−α) × RTT_sampleRTO ← max(RTO_min, β × SRTT)但 α0.125、β2 是 Linux 默认值而 FreeBSD 用 α0.25。更致命的是教材没告诉你第一个 RTT 样本如何初始化 SRTT。RFC 6298 明确规定首个 RTT 样本直接赋给 SRTTRTO 初始化为该样本值的 2 倍。我们用真实抓包数据验证# 在 Ubuntu 22.04 上运行捕获本地回环 TCP 流 sudo tcpdump -i lo -nn port 80 -w tcp_rtt.pcap # 启动一个 HTTP 请求触发 TCP 交互 curl -s http://localhost:8000 /dev/null sudo killall tcpdump # 用 tshark 提取 RTT 样本需先用 tcprewrite 修改时间戳模拟不同 RTT tshark -r tcp_rtt.pcap -Y tcp.analysis.ack_rtt -T fields -e frame.time_epoch -e tcp.analysis.ack_rtt | head -5输出类似1712345678.123456 0.020123 1712345678.143579 0.030456 1712345678.164035 0.025789 1712345678.184821 0.040234 1712345678.205067 0.035678提示tshark 的tcp.analysis.ack_rtt字段依赖于时间戳选项TCP Timestamp Option。若抓包中无 TSopt该字段为空——这意味着第七版答案里所有 RTT 计算题都隐含了“双方启用 TCP 时间戳”的前提。实操中若遇到 RTO 计算结果与答案偏差第一件事就是检查net.ipv4.tcp_timestamps是否为 1。2.3 第 5.31 题快速重传触发条件必须用状态机验证第七版第 5.31 题描述了一个经典场景发送方发出 Seq100,200,300,400 的四个报文段接收方收到 100,300,400 后连续发送三个 ACK200。答案指出此时应触发快速重传。但“连续三个 ACK200”在现实中如何判定Linux 内核通过tcp_send_dupack()统计tp-dup_acks当tp-dup_acks 3且tp-retrans_out 0时调用tcp_retransmit_skb()。我们用 eBPF 验证这一逻辑# bpf_tcp_dupack.py from bcc import BPF bpf_code #include uapi/linux/ptrace.h #include net/tcp.h int trace_tcp_send_dupack(struct pt_regs *ctx, struct sock *sk, struct sk_buff *skb) { struct tcp_sock *tp tcp_sk(sk); bpf_trace_printk(dup_acks: %d, retrans_out: %d\\n, tp-dup_acks, tp-retrans_out); return 0; } b BPF(textbpf_code) b.attach_kprobe(eventtcp_send_dupack, fn_nametrace_tcp_send_dupack) print(Tracing tcp_send_dupack... Ctrl-C to exit.) try: b.trace_print() except KeyboardInterrupt: exit()运行此脚本后用hping3 -S -p 80 -i u10000 127.0.0.1发送 SYN 包制造 Dup ACK需提前关闭 SYN Cookie你会看到内核打印dup_acks: 3, retrans_out: 0——这正是第七版答案第 31 题所依赖的状态机入口条件。没有这个 eBPF 验证你永远不知道“连续三个”在内核里是用dup_acks计数器实现的而非简单比较 ACK 号。3. 第 4 章网络层IP 分片与重组的边界条件必须用 raw socket 实测3.1 第 4.18 题MTU 与分片偏移量的整除陷阱第七版第 4.18 题给出一个 4000 字节的 IP 数据报经 MTU1500 的链路转发要求写出各分片的标识符、标志位、片偏移。标准答案列出三个分片1500、1500、1000 字节。但问题在于IP 首部 20 字节不计入分片载荷而片偏移单位是 8 字节。因此第一个分片载荷 1500 - 20 1480 字节1480 ÷ 8 185片偏移185第二个分片同理片偏移185 185 370第三个分片载荷1000-20980980÷8122.5 → 向下取整为 122片偏移370122492。这个 122.5 必须向下取整否则接收方重组失败。我们用 raw socket 强制构造非法偏移验证from scapy.all import * # 构造第一个分片正常偏移 185 frag1 IP(dst127.0.0.1, id12345, flagsMF, frag185) / (X*1480) # 构造第二个分片故意设偏移为 370.5 → 实际写入 370scapy 自动取整 frag2 IP(dst127.0.0.1, id12345, flagsMF, frag370) / (X*1480) # 构造第三个分片设偏移为 492.5 → 写入 492但载荷仅 960 字节非 980 frag3 IP(dst127.0.0.1, id12345, flags0, frag492) / (X*960) # 发送三帧 send(frag1, verbose0) send(frag2, verbose0) send(frag3, verbose0) # 用 tcpdump 捕获观察内核是否丢弃第三帧 # 若出现 IP Reassembly: fragment overlap 日志则证明偏移计算错误注意Scapy 在构造frag字段时自动向下取整但如果你用 C 写 raw socketip_off字段是 13 位无符号整数写入 492.5 会截断为 492 ——这正是第七版答案强调“片偏移必须为整数”的底层原因。实操中若发现分片重组失败第一检查项就是frag值是否被意外截断。3.2 第 4.22 题ICMP 差错报文必须携带原始 IP 首部前 8 字节 TCP第七版第 4.22 题要求画出 ICMP 目的不可达报文的结构。答案给出“包含引发差错的 IP 首部 前 8 字节 TCP 首部”。但关键细节是这 8 字节必须包含 TCP 的源端口、目的端口、序列号低 16 位。我们用 iptables 触发 ICMP 并抓包验证# 阻止目标端口触发 Destination Unreachable sudo iptables -A OUTPUT -p tcp --dport 9999 -j REJECT --reject-with icmp-host-unreachable # 发送一个 TCP 包到不存在的端口 echo test | nc -w 1 -q 1 127.0.0.1 9999 2/dev/null # 抓取 ICMP 报文提取嵌入的 TCP 首部 sudo tcpdump -i lo icmp -A -c 1 | grep -A 5 0x0000输出中会看到类似0x0000: 4500 0034 0000 0000 4006 0000 7f00 0001 E..4........... 0x0010: 7f00 0001 0019 270f 0000 0000 0000 0000 ............... 0x0020: 5002 0000 0000 0000 0000 0000 0000 0000 P...............其中0x0010行的0019 270f即 TCP 源端口25和目的端口99990000 0000是序列号低 16 位 ——完全匹配第七版答案要求的“前 8 字节”。若你用 Wireshark 打开抓包文件在 ICMP 报文详情里展开 “Internet Control Message Protocol” → “Original IP header” → “Original TCP header”就能直观看到这 8 字节的位置。这是排查防火墙策略失效的核心依据当 ICMP 差错报文缺失这 8 字节上层应用无法关联到原始连接。3.3 第 4.25 题ARP 缓存超时必须用 /proc/sys/net/ipv4/neigh 接口验证第七版第 4.25 题讨论 ARP 缓存的有效期。答案给出“通常为 15 分钟未使用则老化”。但 Linux 中这个值由gc_stale_time控制且受base_reachable_time_ms动态影响。我们直接读取内核参数# 查看默认 ARP 老化时间秒 cat /proc/sys/net/ipv4/neigh/lo/gc_stale_time # 输出60即 60 秒非教材说的 15 分钟 # 查看当前 ARP 缓存条目及其状态 ip neigh show dev lo # 强制刷新并观察状态变化 ip neigh flush dev lo ping -c 1 127.0.0.1 /dev/null ip neigh show dev lo # 状态为 REACHABLE # 等待 61 秒后再次查看 sleep 61 ip neigh show dev lo # 状态变为 STALE第七版答案说“15 分钟”是理论值而实际系统中gc_stale_time默认 60 秒。更关键的是STALE状态下首次访问会触发 ARP 请求但不会阻塞上层——这解释了为什么教材习题中“ARP 缓存失效后首包延迟”现象存在而后续包正常。若你在线上环境发现 ARP 缓存异常不要只查arp -a必须用ip neigh看状态码并确认/proc/sys/net/ipv4/neigh/*/gc_stale_time的实际值。4. 第 7 章应用层HTTP/2 帧解析与流控参数必须对照 RFC 7540 验证4.1 第 7.15 题HEADERS 帧的压缩上下文必须用 hpack 库解码第七版第 7.15 题要求分析 HTTP/2 HEADERS 帧的 HPACK 压缩。答案给出静态表索引 2:method: GET和动态表插入。但真实 WireShark 抓包中HEADERS 帧的 payload 是二进制流需用 HPACK 解码。我们用 Python hpack 库还原import hpack from scapy.all import * # 从真实抓包中提取 HEADERS 帧 payload十六进制字符串 headers_payload_hex 82864401 # 示例静态索引 2 6 动态索引 4 literal name/value headers_payload bytes.fromhex(headers_payload_hex) # 初始化 HPACK 解码器需同步客户端/服务器动态表 decoder hpack.Decoder() # 解码 try: headers decoder.decode(headers_payload) print(Decoded headers:, headers) # 输出: [(:method, GET), (:path, /index.html)] except hpack.HPACKError as e: print(HPACK decode failed:, e)关键点在于第七版答案里“动态表索引 4”对应的是:path字段但其索引值取决于此前已插入的条目数。若你用 curl 发送请求curl --http2 -v https://http2.example.comWireshark 中右键 HEADERS 帧 → “Decode As” → “HTTP/2”就能看到自动解码的头部——这验证了答案中“索引随会话动态变化”的结论。没有这个解码步骤你永远不知道教材写的“索引 4”在真实流量中对应什么。4.2 第 7.19 题SETTINGS 帧的初始窗口大小必须用 tcpdump 确认第七版第 7.19 题指出 HTTP/2 初始流控窗口为 65535 字节。但 RFC 7540 规定SETTINGS 帧可携带SETTINGS_INITIAL_WINDOW_SIZE参数服务端可将其设为更大值如 1MB。我们用 tcpdump 抓取 TLS 握手后的 SETTINGS 帧# 抓取 HTTP/2 连接需支持 ALPN openssl s_client -alpn h2 -connect http2.example.com:443 2/dev/null /dev/null | \ tcpdump -i any -w h2_settings.pcap port 443 # 用 tshark 解析 SETTINGS 帧 tshark -r h2_settings.pcap -Y http2.type 4 -T fields -e http2.settings.initial_window_size若输出为空说明服务端未显式设置采用默认 65535若输出1048576则证明第七版答案中的“65535”只是协议默认值线上环境可能完全不同。这是排查 HTTP/2 流控阻塞的关键当curl --http2 -v显示“stream closed by peer”首先要检查 SETTINGS 帧里的initial_window_size是否过小。4.3 第 7.22 题PRIORITY 帧的依赖权重必须用 wireshark 可视化验证第七版第 7.22 题要求画出 PRIORITY 帧结构。答案给出“依赖流 ID 排名权重”。但真实场景中权重影响浏览器渲染顺序。我们用 Chrome DevTools 的 Network 面板验证打开 Chrome访问支持 HTTP/2 的网站如 https://http2.akamai.com/F12 → Network → 右键表头 → “Response Headers” → 勾选 “Priority”刷新页面观察各资源的 Priority 列u1表示最高优先级HTMLu4表示低优先级图片此时用 Wireshark 抓包过滤http2.type 2PRIORITY 帧展开帧详情能看到Stream Dependency和Weight字段。第七版答案中“权重范围 1~256”在此处得到印证Chrome 设置的Weight256对应最高优先级。若你发现 CSS 加载慢于 JS检查 PRIORITY 帧的Weight值是否被 CDN 错误覆盖——这比单纯看答案更能理解“优先级”在真实链路中的作用。5. 避坑七个血泪经验总结——为什么你按答案算出的 RTO 总是不对5.1 现象第 5.27 题 RTO 计算结果与 Wireshark 显示值偏差 20%原因Wireshark 的tcp.analysis.rtt字段基于时间戳选项TSopt计算而教材题干默认启用 TSopt但你的抓包环境net.ipv4.tcp_timestamps0。解决执行sudo sysctl -w net.ipv4.tcp_timestamps1重启抓包。验证命令cat /proc/sys/net/ipv4/tcp_timestamps输出 1。5.2 现象第 4.18 题分片重组失败内核日志报 “IPv4: drop fragment”原因Scapy 构造分片时frag字段未对齐 8 字节边界或flagsMF在最后一个分片中未清零。解决用ip frag字段时确保(payload_len) % 8 0最后一个分片设flags0非DF或MF。5.3 现象第 7.15 题 HPACK 解码失败提示 “Invalid Huffman code”原因HTTP/2 连接使用了 QPACKQUIC 的压缩方案而第七版答案基于 HPACK。解决确认抓包协议为 HTTP/2非 HTTP/3Wireshark 中右键帧 → “Decode As” → 强制设为 HTTP/2。5.4 现象第 5.31 题快速重传未触发tcpdump显示只有两个 Dup ACK原因Linux 内核tcp_reordering默认值为 3但若网络乱序严重内核可能将第 3 个 ACK 判定为乱序而非丢包。解决临时调大net.ipv4.tcp_reordering6再测试线上环境应监控netstat -s | grep -i reorders。5.5 现象第 4.22 题 ICMP 差错报文中缺失 TCP 端口号原因触发 ICMP 的设备如防火墙未实现 RFC 1812 要求的“携带原始传输层首部”。解决改用iptables -j REJECT --reject-with icmp-host-unreachableLinux 内核原生实现避免第三方防火墙。5.6 现象第 7.19 题 SETTINGS 帧显示initial_window_size0原因服务端主动将初始窗口设为 0 以实施流控符合 RFC 7540 Section 6.9.2。解决这不是错误而是主动策略客户端需等待WINDOW_UPDATE帧后才能发送数据。5.7 现象第 5.23 题 ssthresh 计算结果与ss -i输出不符原因ss -i显示的是当前snd_ssthresh但第七版答案计算的是“理论值”未考虑tcp_slow_start_after_idle0等内核参数影响。解决用cat /proc/sys/net/ipv4/tcp_slow_start_after_idle确认是否禁用空闲后慢启动若为 0则 ssthresh 不会因空闲重置。6. 把答案变成调试器用第七版课后题构建自己的协议验证工作台6.1 用第 3 章习题搭建以太网帧解析流水线第七版第 3 章聚焦以太网 MAC 帧结构其中第 3.12 题要求计算 CRC-32 校验码。与其背公式不如用libpcap直接提取帧并验证// eth_crc_check.c #include pcap.h #include stdio.h #include stdlib.h #include string.h // CRC-32 lookup table (IEEE 802.3) static const uint32_t crc32_table[256] { /* 256-entry table */ }; uint32_t eth_crc32(const uint8_t *data, size_t len) { uint32_t crc 0xFFFFFFFF; for (size_t i 0; i len; i) { crc (crc 8) ^ crc32_table[(crc ^ data[i]) 0xFF]; } return crc ^ 0xFFFFFFFF; } int main(int argc, char *argv[]) { if (argc ! 2) { fprintf(stderr, Usage: %s pcap_file\n, argv[0]); return 1; } pcap_t *handle pcap_open_offline(argv[1], errbuf); struct pcap_pkthdr *header; const u_char *packet; while (pcap_next_ex(handle, header, packet) 0) { // Ethernet frame: dst(6) src(6) type(2) payload fcs(4) if (header-len 18) { // min frame without FCS uint32_t calc_fcs eth_crc32(packet, header-len - 4); uint32_t wire_fcs *(uint32_t*)(packet header-len - 4); printf(Frame %d: calc%08x, wire%08x, %s\n, packet_count, calc_fcs, wire_fcs, calc_fcs wire_fcs ? OK : BAD); } } pcap_close(handle); return 0; }编译运行gcc -o eth_crc eth_crc_check.c -lpcap再用./eth_crc capture.pcap。你会发现第七版第 3.12 题的答案CRC 值在真实帧中总能匹配——因为教材所有 CRC 计算题都基于 IEEE 802.3 标准的多项式0x04C11DB7而libpcap抓包保留了原始 FCS 字段。这个 C 程序就是你的第 3 章实体化工具它把抽象的 CRC 计算变成可执行、可调试、可集成到 CI 的验证环节。6.2 用第 6 章习题构建路由协议状态机图谱第七版第 6 章 OSPF/BGP 习题如第 6.18 题 BGP 路径属性排序常被当作记忆题。但真正的价值在于用bird或quagga的 CLI 实时验证状态迁移# 启动 bird 守护进程配置见 bird.conf sudo bird -c /etc/bird/bird.conf -d # 进入 bird CLI查看 BGP 邻居状态 sudo birdc show route protocol bgp show protocols all bgp1 # 关键命令查看 BGP FSM 状态 show bfd sessions show ospf state第七版第 6.18 题答案说“LOCAL_PREF AS_PATH ORIGIN”但这只是决策顺序。真实bird日志中你会看到bgp1: State changed to Established后紧接着bgp1: Imported 12 routes——这证明路径属性排序已在内核路由表中生效。把教材答案和birdc输出并排打开一边看答案里的属性优先级表一边看 CLI 里show route的via和pref字段协议行为就从纸面落到了终端。6.3 用第 8 章习题建立网络安全实验沙箱第七版第 8 章密码学习题如第 8.7 题 RSA 密钥生成看似纯数学但结合openssl就能构建攻击验证环境# 生成 512 位 RSA 密钥弱密钥用于教学 openssl genrsa -3 -out weak.key 512 # 提取公钥并导出为 PEM openssl rsa -in weak.key -pubout -out weak.pub # 用 rsatool 分解模数演示教材第 8.7 题的分解过程 # pip install rsatool rsatool -o cracked.key -e 65537 -n $(openssl rsa -in weak.key -noout -modulus | cut -d -f2 | xargs) # 验证私钥有效性 openssl pkey -in cracked.key -text -noout第七版第 8.7 题的答案给出分解步骤而rsatool将其自动化。当你看到cracked.key成功生成就真正理解了“密钥长度不足导致分解可行”——这比背诵“RSA-2048 安全”有力得多。我每次讲密钥管理都让学生先跑通这个流程再对比openssl genrsa -out strong.key 2048的不可分解性。安全不是概念是rsatool跑了 3 小时仍返回Failed的沉默。从那以后我每次带新人都强制走一遍这三步用 Scapy 验证 TCP 状态机、用birdc对照 BGP 属性表、用rsatool破解弱密钥。不是为了炫技而是让第七版课后答案从“参考答案”变成“协议调试器”——它不再是你合上书就消失的纸页而是你敲tcpdump时脑中自动浮现的 cwnd 曲线是你看ip neigh时秒懂的 STALE 状态是你 debug HTTP/2 流控时第一反应去查的SETTINGS_INITIAL_WINDOW_SIZE。希望帮到你。本文还有配套的精品资源点击获取