简介:这份资源是广东工业大学计算机学院2015年计算机网络课程的实验报告PDF,面向正在修读计算机网络实验、需要参考实验流程与报告写法的本科生,尤其适合使用GNS3开展交换机与VLAN实验的同学。压缩包内仅含1个PDF文件,大小约1.17MB,内容以图文形式记录实验过程与结果,便于直接查阅和打印。报告围绕GNS3安装使用与交换机技术展开,涵盖网络拓扑搭建、设备基础操作、交换机配置、VLAN划分及VLAN间通信等实验目的,并附有同VLAN与跨VLAN连通性测试的截图与说明,还记录了通过Wireshark抓取Trunk流量、分析IEEE 802.3帧结构与CDP协议标签的过程。读者可借此了解实验报告的完整结构、测试步骤与结果分析写法,对照自己的实验环境查漏补缺。目前已有71人学习,适合作为课程实验的参考范例。
1. 一份实验报告为什么值得当成工程手册来读
很多人看到“广工2015年计算机网络实验报告.pdf”这个文件名,第一反应是:这不就是一份学生作业吗,有什么好看的。但如果你真正带过新人、或者自己从抓包开始学网络,就会知道这类实验报告里藏着一套非常完整的“从零把协议跑起来”的路径。它通常覆盖 socket 编程、TCP/UDP 对比、抓包分析、HTTP 请求构造、路由与子网划分这几块,恰好是网络工程里最核心的基本功。问题在于,报告本身是给老师看的,步骤跳跃、环境依赖没写清、参数含义一笔带过,直接照着做大概率卡在环境配置和结果对不上这两步。这篇笔记要做的,就是把这类实验报告拆成一份能复现、能排错、能迁移到真实工作的操作手册,适合刚入行的网络方向新人,也适合想补底层协议的开发同学。
2. 先搞清楚实验环境:抓包工具与 socket 编程的选型逻辑
2.1 为什么 2015 年前后的实验报告默认用 Wireshark + C 语言 socket
那个年代的计算机网络实验,绝大多数学校用的是 Wireshark 做协议分析,用 C 语言在 Linux 或 Windows 下写 socket 程序。这不是随便选的。Wireshark 能直接看到 TCP 三次握手的每一个标志位,socket 编程则逼着你手动处理字节序、地址结构体和缓冲区。这两样东西配合起来,协议就不再是课本上的图,而是你能改一个参数就观察到行为变化的东西。现在有人用 Python 的 scapy 或 socket 库替代,效率更高,但如果你要理解底层,C 语言那套 struct sockaddr_in、htons、inet_pton 还是绕不过去。我一般建议:抓包用 Wireshark,写协议交互先用 Python 快速验证逻辑,再回头看 C 版本对照理解内存布局。
2.2 最小可复现环境搭建:三台虚拟机就够
不需要真实路由器,也不需要公网 IP。用 VMware 或 VirtualBox 开三台 Linux 虚拟机,一台做客户端,一台做服务端,一台做“中间人”跑抓包。网络模式选 Host-Only 或 NAT,保证三台能互相 ping 通即可。具体步骤:
# 在服务端虚拟机上查看 IP,确认网段 ip addr show | grep "inet " # 假设得到 192.168.56.101 # 在客户端虚拟机上 ping 服务端,确认连通 ping -c 3 192.168.56.101 # 在第三台虚拟机上启动 Wireshark,选择 Host-Only 对应的网卡 sudo wireshark逻辑说明:Host-Only 模式让三台机器在同一个虚拟交换机下,流量不会跑到物理网络,抓包干净。参数上唯一要注意的是网卡名字,Linux 下通常是 ens33 或 enp0s3,选错了什么都抓不到。如果 ping 不通,先检查防火墙:sudo ufw status,临时关闭用sudo ufw disable,实验完再开回来。
2.3 实验报告里最容易缺的一步:时间同步与抓包过滤
报告通常只写“启动 Wireshark 抓包”,但没告诉你抓包过滤器怎么写。三台机器同时跑,不设过滤会抓到大量无关流量。正确做法是在 Wireshark 的捕获过滤器里写host 192.168.56.101 and tcp port 8080,只抓目标服务端的指定端口。另外,虚拟机时间不同步会导致你按时间戳对不上客户端和服务端的日志。实验前统一执行sudo ntpdate pool.ntp.org或手动date -s对齐到同一分钟。这一步报告里基本不写,但不做的话,后面分析时序会非常痛苦。
3. TCP 与 UDP 实验:从代码到抓包结果的完整对照
3.1 用 Python 写最小 TCP 回声服务端与客户端
实验报告里的 C 代码往往几十行,夹杂错误处理,新手容易迷失。先用 Python 把逻辑跑通,再对照 C 版本看差异。服务端:
# tcp_server.py import socket HOST = '0.0.0.0' # 监听所有网卡,方便虚拟机之间访问 PORT = 8080 with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # 避免重启时端口占用 s.bind((HOST, PORT)) s.listen(1) print(f"TCP server listening on {PORT}") conn, addr = s.accept() with conn: print(f"Connected by {addr}") while True: data = conn.recv(1024) if not data: break conn.sendall(data) # 原样回发,形成回声客户端:
# tcp_client.py import socket HOST = '192.168.56.101' # 改成你的服务端 IP PORT = 8080 with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.connect((HOST, PORT)) s.sendall(b'Hello, TCP') data = s.recv(1024) print('Received:', data.decode())逻辑说明:SO_REUSEADDR是关键参数,不加的话服务端每次重启都要等 60 秒 TIME_WAIT。recv(1024)的 1024 是缓冲区大小,实验里发短消息够用,但如果你要测大文件传输,这个值会影响吞吐,一般调到 4096 或 65536。客户端connect之后,Wireshark 里应该立刻看到三次握手:SYN、SYN-ACK、ACK。
3.2 在 Wireshark 里验证三次握手与四次挥手
启动抓包后运行客户端,过滤tcp.port == 8080。你应该看到:
| 序号 | 方向 | 标志位 | 说明 |
|---|---|---|---|
| 1 | 客户端→服务端 | SYN | 客户端随机初始序列号 |
| 2 | 服务端→客户端 | SYN, ACK | 服务端确认并给出自己的序列号 |
| 3 | 客户端→服务端 | ACK | 握手完成 |
| 4 | 客户端→服务端 | PSH, ACK | 发送 “Hello, TCP” |
| 5 | 服务端→客户端 | PSH, ACK | 回声数据 |
| 6 | 客户端→服务端 | FIN, ACK | 客户端请求关闭 |
| 7 | 服务端→客户端 | ACK | 确认 |
| 8 | 服务端→客户端 | FIN, ACK | 服务端关闭 |
| 9 | 客户端→服务端 | ACK | 最终确认 |
如果只看到前三条没有后续数据,检查客户端sendall是否执行、服务端recv是否阻塞在accept之前。常见翻车点是服务端防火墙没关,SYN 到了但 SYN-ACK 被丢弃,Wireshark 里只看到重传的 SYN。
3.3 UDP 实验的差异点与抓包特征
把上面代码的SOCK_STREAM改成SOCK_DGRAM,去掉listen和accept,服务端用recvfrom和sendto。UDP 没有握手,客户端直接发,服务端直接回。Wireshark 里过滤udp.port == 8080,你会看到每个数据包独立,没有序列号确认机制。实验报告通常要求对比“丢包时 TCP 重传而 UDP 不重传”,验证方法是:在客户端连续发 100 个带序号的数据包,服务端故意sleep或丢弃部分,观察 TCP 版本会自动重传,UDP 版本则永久丢失。这个对比是理解可靠传输最直观的方式。
4. HTTP 与抓包分析:把请求响应拆到字节级
4.1 用 Python 构造原始 HTTP 请求并观察响应头
实验报告里常有一个“手动构造 HTTP 请求”的环节,但很多版本只让你用浏览器。更硬核的做法是用 socket 直接发原始文本:
# raw_http.py import socket HOST = '192.168.56.101' PORT = 80 request = ( "GET /index.html HTTP/1.1\r\n" "Host: 192.168.56.101\r\n" "Connection: close\r\n" "\r\n" ) with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.connect((HOST, PORT)) s.sendall(request.encode()) response = b'' while True: chunk = s.recv(4096) if not chunk: break response += chunk print(response.decode(errors='replace'))逻辑说明:\r\n是 HTTP 协议规定的行结束符,少一个\r或\n服务端可能直接返回 400。Connection: close告诉服务端发完就关,这样recv循环才能靠连接关闭来结束,否则会一直阻塞。参数上,Host头在 HTTP/1.1 里是必须的,没有它很多服务端返回 400。如果你在服务端虚拟机上跑一个简单的python3 -m http.server 80,这个请求就能拿到目录列表。
4.2 用 Wireshark 看 HTTP 请求的 TCP 分段
在 Wireshark 里过滤http,找到你的 GET 请求。展开 TCP 层,你会看到请求可能被分成多个 TCP 段,尤其是请求头较长时。实验报告里常问“为什么一个 HTTP 请求会对应多个 TCP 包”,答案就是 MSS(最大报文段长度)限制。在以太网里 MSS 通常是 1460 字节,超过就分段。你可以通过tcp.len字段看到每个段的数据长度。如果响应很大,还会看到服务端连续发送多个段,客户端逐个 ACK。这个观察能帮你理解“HTTP 是应用层协议,实际传输靠 TCP 分段”这句话的真实含义。
4.3 状态码与重定向的抓包验证
在服务端放一个index.html,再放一个redirect.html内容为<meta http-equiv="refresh" content="0;url=/index.html">。用浏览器访问redirect.html,Wireshark 里会看到两次 GET 请求。第一次返回 200 带 HTML 内容,浏览器解析 meta 标签后发起第二次 GET。如果你用curl -v访问,能看到更清晰的流程。实验报告里如果要求“分析重定向”,记得区分 301/302 服务端重定向和 meta 刷新这种客户端行为,前者在抓包里直接看到 301 响应和 Location 头,后者只是普通 200 响应加一段 HTML。
5. 避坑与排查:实验报告里不会写的五个翻车点
5.1 现象:Wireshark 抓不到任何包,接口列表为空
原因:Linux 下普通用户没有抓包权限,或者选错了网卡。虚拟机里常有 ens33、lo、docker0 多个接口,选到 lo 只能看到本地回环。解决:用sudo wireshark启动,或者在安装时配置dpkg-reconfigure wireshark-common允许非 root 抓包,然后把用户加入 wireshark 组。选接口时先ip addr确认哪个接口有 192.168.56.x 的地址。
5.2 现象:TCP 客户端 connect 返回 Connection refused
原因:服务端没启动,或者服务端绑定了 127.0.0.1 而不是 0.0.0.0。绑定 127.0.0.1 时只有本机可以连,虚拟机之间连不上。解决:检查服务端代码里HOST是否为'0.0.0.0',用ss -tlnp | grep 8080确认监听地址是0.0.0.0:8080而不是127.0.0.1:8080。如果服务端在 Windows 上,还要检查 Windows 防火墙是否放行。
5.3 现象:UDP 服务端收不到数据,但客户端 sendto 没报错
原因:UDP 是无连接的,sendto成功只表示数据交给了本地协议栈,不代表对方收到。常见原因是服务端recvfrom的缓冲区太小,或者服务端绑定的端口和客户端发送的端口不一致。解决:在服务端打印recvfrom的返回值和来源地址,确认数据到了。如果没到,在中间人虚拟机上用tcpdump -i any udp port 8080 -X看数据包是否出现在网络上。
5.4 现象:HTTP 请求返回 400 Bad Request
原因:请求行或请求头格式错误,最常见的是行结束符用了\n而不是\r\n,或者Host头缺失。解决:用print(repr(request))把请求字符串打印出来,逐字节检查。\r\n在 Python 字符串里必须写成\r\n,不能写成\\r\\n。另外,请求行末尾和最后一个头之后必须有一个空行,也就是连续两个\r\n。
5.5 现象:实验报告里的结果和你的抓包对不上,序列号或窗口大小不同
原因:不同操作系统、不同内核版本的 TCP 初始序列号随机算法和窗口缩放因子不同。2015 年的报告可能基于 Windows 7 或 Ubuntu 14.04,你现在用 Windows 11 或 Ubuntu 22.04,默认参数已经变了。解决:不要死磕具体数值,关注相对变化。比如三次握手的标志位顺序、重传的超时时间倍增规律、窗口大小随接收缓冲区的变化趋势,这些是稳定的。如果报告里写了具体序列号,那只是示例,你的环境里一定是不同的随机值。
6. 把实验报告变成可复用的调试脚本:一个自动化验证技巧
实验报告做完就扔,下次遇到网络问题还是从头抓包,这是最大的浪费。我习惯把每个实验的核心验证逻辑写成一个可重复运行的脚本,放在~/netlab/下,用 Makefile 串起来。比如 TCP 回声测试,写一个check_tcp.sh:
#!/bin/bash # check_tcp.sh - 自动验证 TCP 回声服务是否正常 SERVER_IP=${1:-192.168.56.101} PORT=${2:-8080} # 启动服务端(后台) python3 tcp_server.py & SERVER_PID=$! sleep 1 # 运行客户端并捕获输出 OUTPUT=$(python3 tcp_client.py 2>&1) echo "$OUTPUT" # 验证是否收到回声 if echo "$OUTPUT" | grep -q "Received: b'Hello, TCP'"; then echo "[PASS] TCP echo works" else echo "[FAIL] TCP echo broken" fi kill $SERVER_PID逻辑说明:${1:-默认值}是 bash 的参数默认值语法,不传参就用默认 IP 和端口。sleep 1给服务端启动留时间,虚拟机慢的话调到 2。grep -q静默匹配,只靠退出码判断。这个脚本可以扩展成测试 UDP、HTTP、甚至模拟丢包。参数上,如果你在 CI 里跑,把sleep换成轮询ss -tln检查端口是否监听,更可靠。
更进一步,用tcpdump在后台抓包,脚本结束时自动生成 pcap 文件,配合tshark命令行分析:
# 后台抓包,只抓 8080 端口,最多 100 个包 sudo tcpdump -i any -w /tmp/tcp_echo.pcap -c 100 port 8080 & TCPDUMP_PID=$! # ... 运行测试 ... kill $TCPDUMP_PID # 用 tshark 统计握手次数 tshark -r /tmp/tcp_echo.pcap -Y "tcp.flags.syn==1 and tcp.flags.ack==0" | wc -l这个技巧的价值在于:下次你换了一台机器、换了一个内核,跑一遍脚本就知道协议行为有没有变化。实验报告里的结论是静态的,但你的验证脚本是活的。我自己的习惯是每做完一个实验,就把关键命令和预期输出写进脚本注释里,半年后回头看,比翻报告快得多。希望帮到你。
本文还有配套的精品资源,点击获取