简介:本资源是哈尔滨工业大学计算机网络课程配套的全套实验材料,面向高校计算机及相关专业本科生,覆盖网络协议原理理解、服务端开发与抓包分析等核心实践能力训练。内容完整包含6个经典实验:HTTP代理服务器设计、HTTP分组收发与转发、GBN可靠传输协议实现、Wireshark协议分析、简单网络组建与配置,每项均含详实实验报告(docx)与可运行源码(js/cpp),辅以README说明、配置文件(json/.babelrc)及网络拓扑pkt文件,便于复现实验环境与调试验证。压缩包共22个文件,以6份docx报告、7个js前端逻辑脚本、3个cpp协议实现代码为主,另有md文档、json配置及pkt抓包文件,总大小4.67MB,结构清晰、开箱即用。已有563人学习下载,适合课程预习复习、实验课参考、协议原理巩固及网络编程入门实践。
1. 哈工大计算机网络实验1-6:一套能跑通、能调试、能交作业的完整工程包
你是不是也经历过:老师刚布置完“用C++实现GBN协议”,手头只有一页伪代码和模糊的实验指导书?Wireshark抓了一堆HTTP包,却分不清哪个是代理转发、哪个是原始请求?改了三遍ipv4.cpp,school.pkt在Packet Tracer里死活不转发——最后发现只是子网掩码少写了个0?这套哈工大计算机网络实验1-6的压缩包,不是零散笔记,也不是截图拼凑的PDF,而是一套带可执行源码、配套抓包验证数据、含逐层注释报告、且全部通过本地环境实测运行的闭环资源。它覆盖从HTTP代理服务器(实验1)、分组收发与转发(实验2–3)、GBN可靠传输(实验4)、Wireshark协议深度分析(实验5)到Packet Tracer网络拓扑搭建(实验6)的全链路。适合正在啃计网实验、需要快速验证逻辑、或想对照标准实现查漏补缺的本科生与自学开发者——尤其当你卡在sendto()返回-1、recvfrom()阻塞超时、或.pkt文件加载后设备灯不亮时,这份资源里的app.cpp编译日志、export.docx中的Wireshark过滤表达式、以及README.md里明确标注的GNS3/Packet Tracer版本兼容说明,就是你翻车现场的后悔药。
2. 实验1–3:HTTP代理与分组收发——从app.js到ipv4.cpp的三层通信验证
2.1 HTTP代理服务器:Node.js实现与端口绑定陷阱
实验1的核心是app.js(非浏览器端JS,而是Node.js服务端脚本),它实现了基础HTTP代理功能:接收客户端请求 → 解析Host头 → 转发至目标服务器 → 回传响应。关键不在“能转发”,而在“能被Wireshark精准捕获”。常见错误是监听0.0.0.0:8080却未关闭系统自带的Web服务冲突,导致EADDRINUSE。正确做法是显式指定本机IP并检查端口占用:
# 先查端口占用(Linux/macOS) lsof -i :8080 # 或 Windows netstat -ano | findstr :8080 # 启动时绑定具体IP(如本机IPv4为192.168.1.100) node app.js --host 192.168.1.100 --port 8080提示:
app.js中http.createServer()的req.socket.remoteAddress必须打印到控制台,这是后续Wireshark比对客户端真实IP的唯一依据;若此处显示::1(IPv6回环),说明请求根本没走代理,而是直连了本地服务。
2.2 分组收发实验:ipv4.cpp的原始套接字权限与ICMP校验
实验2与实验3共用ipv4.cpp,它用原始套接字(Raw Socket)构造并发送自定义IP数据包。这里踩坑率高达70%:
- Linux下需
sudo权限(sudo ./a.out),否则socket(AF_INET, SOCK_RAW, IPPROTO_RAW)直接返回-1; - Windows需启用
SeCreateGlobalPrivilege(通过ntrights.exe或组策略),普通管理员权限不够; - 更隐蔽的是ICMP校验和计算:
ipv4.cpp中checksum()函数对IP首部长度字段(IHL)的处理必须是header_length * 4,而非直接取ip_header->ihl——因为该字段单位是4字节,值为5表示20字节,但代码里若误写ip_header->ihl * 5就会校验失败,目标主机静默丢包。
// ipv4.cpp 关键修正段(原版易错点) uint16_t checksum(uint16_t *addr, int len) { uint32_t sum = 0; while (len > 1) { sum += *addr++; len -= 2; } if (len == 1) sum += *(uint8_t*)addr; while (sum >> 16) sum = (sum & 0xFFFF) + (sum >> 16); return (uint16_t)(~sum); } // 构造IP首部时,IHL字段必须按规范设置 ip_header->ihl = 5; // 表示首部20字节,不可写成 ip_header->ihl = 20; ip_header->tot_len = htons(20 + data_len); // 总长=首部20+数据长度2.3 分组转发实验:双网卡配置与路由表干预
实验3要求实现“转发”而非“发送”,即本机作为中间节点透传数据包。这要求系统开启IP转发,并手动添加路由规则。export.docx中给出的命令仅适用于Ubuntu 20.04,新版内核需额外处理:
# 1. 开启IPv4转发(临时) echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward # 2. 永久生效(写入/etc/sysctl.conf) echo "net.ipv4.ip_forward = 1" | sudo tee -a /etc/sysctl.conf sudo sysctl -p # 3. 关键:添加策略路由(避免回环) # 假设eth0接客户端(192.168.1.0/24),eth1接服务器(10.0.0.0/24) sudo ip rule add from 192.168.1.0/24 table 100 sudo ip route add 10.0.0.0/24 via 10.0.0.1 dev eth1 table 100注意:若跳过第3步,
ipv4.cpp发出的数据包会被本机路由表直接投递到lo接口,Wireshark在eth0上抓不到转发流——这是实验3失败最隐蔽的原因。
3. 实验4:GBN协议实现——滑动窗口状态机与超时重传的硬核调试
3.1 GBN核心逻辑:发送方窗口与ACK确认的严格同步
code/目录下的GBN实现(gbn_sender.cpp与gbn_receiver.cpp)采用经典状态机设计。其难点不在算法本身,而在时间戳驱动的超时重传与ACK乱序到达的冲突处理。原版代码中sender_timeout_handler()存在一个致命缺陷:当连续收到多个重复ACK(如ACK=2)时,若未清空已确认序列号队列,会导致窗口左边界卡死,新数据无法发送。修复方案是在每次处理ACK后强制推进窗口:
// gbn_sender.cpp 中 ACK处理逻辑修正 void handle_ack(int ack_seq) { if (ack_seq >= window_base && ack_seq < window_base + WINDOW_SIZE) { // 清除已确认包的定时器 cancel_timer(ack_seq); // 关键:推进窗口基线(原版缺失此行) while (window_base <= ack_seq) { window_base++; if (window_base > ack_seq) break; } // 触发新数据发送 send_new_packets(); } }3.2 抓包验证:Wireshark过滤表达式与序列号映射
实验4要求用Wireshark验证GBN行为,但原始export.docx中只写了tcp.port == 8080,这完全无效——GBN使用UDP自定义协议,无TCP端口概念。必须基于UDP载荷内容过滤:
| 过滤目标 | Wireshark Display Filter | 说明 |
|---|---|---|
| 所有GBN数据包 | udp.dstport == 9999 && udp.length > 28 | 实验约定目的端口9999,且最小包含8字节头部+20字节数据 |
| 发送方重传包 | udp.dstport == 9999 && udp.payload[12:4] == 01:00:00:00 | 自定义头部第12–15字节为标志位,0x01000000表示重传(原版协议定义) |
| 接收方ACK包 | udp.srcport == 9999 && udp.payload[8:4] == 00:00:00:00 | 第8–11字节为ACK类型标识,0x00000000表示ACK |
血泪经验:Wireshark默认不解析UDP载荷,需右键UDP包 → “Decode As…” → 将端口9999强制设为“Raw”才能看到十六进制载荷,否则
payload[12:4]过滤永远为空。
3.3 超时参数调优:RTT估算与初始RTO设置
GBN性能高度依赖超时重传时间(RTO)。原版gbn_sender.cpp将RTO硬编码为1000ms,但在千兆局域网中这会导致过度重传。应改为基于RTT采样的动态RTO:
// 在 sender.cpp 中添加 RTT 采样逻辑 struct timespec start_time; clock_gettime(CLOCK_MONOTONIC, &start_time); // 发送时记录时间戳(存入包头部) packet.header.timestamp = start_time.tv_sec * 1000000 + start_time.tv_nsec / 1000; // 收到ACK时计算RTT struct timespec end_time; clock_gettime(CLOCK_MONOTONIC, &end_time); long rtt_us = (end_time.tv_sec - start_time.tv_sec) * 1000000 + (end_time.tv_nsec - start_time.tv_nsec) / 1000; update_rto(rtt_us); // 使用RFC6298算法更新RTO4. 实验5:Wireshark协议分析——从抓包到报文字段级解读的落地路径
4.1 HTTP代理流量分离:三元组过滤与会话追踪
实验5要求分析代理场景下的HTTP交互,但Wireshark默认将代理请求与目标服务器响应混在同一会话。必须用四元组(源IP:端口 + 目标IP:端口)精确隔离:
# 过滤代理服务器自身流量(假设代理运行在192.168.1.100:8080) ip.addr == 192.168.1.100 && tcp.port == 8080 # 过滤客户端到代理的请求(客户端IP为192.168.1.50) ip.src == 192.168.1.50 && tcp.dstport == 8080 # 过滤代理到目标服务器的请求(目标为httpbin.org,IP假设为34.123.45.67) ip.src == 192.168.1.100 && ip.dst == 34.123.45.67 && tcp.dstport == 80提示:在
report.docx中,所有HTTP请求的Host头与GET路径必须与Wireshark中http.request.full_uri字段完全一致——这是验证代理是否正确解析并转发的关键证据。
4.2 TCP三次握手与四次挥手的时序断点
实验5强调“可靠连接建立与释放过程”,但学生常把SYN、SYN-ACK、ACK当成独立事件。实际应关注时间轴上的微秒级间隔:
- 正常局域网中,SYN→SYN-ACK延迟应<1ms,若>10ms说明网络拥塞或代理中间件介入;
- FIN-WAIT-1状态持续时间若>60s,表明对方未响应FIN,可能进程崩溃或防火墙拦截;
export.docx中提供的tcp.analysis.flags过滤器(如tcp.analysis.retransmission)必须配合Statistics → Flow Graph使用,才能可视化重传位置。
4.3 避坑:Wireshark常见问题与排查
现象 → 原因 → 解决:
现象:Wireshark抓不到任何HTTP包,但浏览器能正常访问。
原因:代理设置错误(如Chrome设置了系统代理但Firefox未设),或app.js未监听正确IP。
解决:在浏览器地址栏输入http://127.0.0.1:8080/test.html直连代理,同时Wireshark过滤http && ip.addr == 127.0.0.1。现象:抓到大量
TCP Retransmission但代理功能正常。
原因:Wireshark在高负载下丢包,或网卡驱动未启用巨型帧(Jumbo Frame)。
解决:降低抓包缓冲区大小(Edit → Preferences → Capture → Buffer size = 2MB),并禁用网卡节能模式。现象:
http.request.uri显示/但实际访问的是/api/data。
原因:HTTP/2协议下URI被HPACK压缩,Wireshark默认不解析。
解决:强制浏览器使用HTTP/1.1(Chrome启动参数加--unsafely-treat-insecure-origin-as-secure="http://127.0.0.1:8080" --user-data-dir=/tmp/chrome-test --unsafely-allow-http-for-local-testing)。
5. 实验6:Packet Tracer网络组建——school.pkt拓扑验证与故障注入技巧
5.1 school.pkt拓扑结构与设备角色定义
experiment-6/school.pkt构建了一个典型校园网模型:
- 核心层:Router0(运行OSPF,连接各区域);
- 汇聚层:Switch0(VLAN 10:教师办公区;VLAN 20:学生机房);
- 接入层:PC0(教师PC,IP 192.168.10.10)、PC1(学生PC,IP 192.168.20.10);
- 外联:Router1(模拟Internet,配置静态路由指向Router0)。
关键验证点是跨VLAN通信:PC0 ping PC1必须成功,且Wireshark在Router0的G0/0接口应捕获到802.1Q标签帧(VLAN ID=10/20)。
5.2 故障注入:模拟真实网络问题并定位
README.md中隐藏了一个教学技巧:通过手动制造故障,训练排错能力。例如:
- 步骤1:在Switch0上删除VLAN 20的SVI接口(
no interface vlan 20); - 步骤2:观察PC1的
ping 192.168.10.10持续超时; - 步骤3:在Router0上执行
show ip route,发现无192.168.20.0/24路由; - 步骤4:在Switch0上恢复VLAN 20并配置
interface vlan 20,再show vlan brief确认PC1端口已加入。
注意:Packet Tracer 7.3.1以上版本中,
show running-config输出的VLAN配置必须包含switchport access vlan 20,若缺失则PC1实际处于VLAN 1,导致跨VLAN失败。
5.3 配置同步:避免Packet Tracer与GNS3的版本鸿沟
school.pkt在Packet Tracer 7.2.1中可完美运行,但若用GNS3 2.2.x导入,会出现路由器无法启动问题。根本原因是IOS镜像不兼容:
- Packet Tracer使用精简版IOS(
pt124-2.bin),仅支持基础命令; - GNS3需完整IOS(如
c3640-a3jk9s-mz.124-25d.image),且内存需≥192MB。
解决方案:在GNS3中新建路由器时,选择c3640平台,分配256MB RAM,挂载完整IOS,并在启动配置中禁用ip cef(Packet Tracer不支持CEF加速)。
6. 从源码到报告:一份实验资源的闭环验证方法论与我的强制习惯
真正让这套资源区别于网上泛滥的“答案集”的,是它内置的三层验证锚点:源码可编译、抓包可复现、报告可溯源。我曾帮某高校实验室重构计网实验体系,发现学生交的报告里90%的Wireshark截图来自百度图片,而export.docx中每张图都带时间戳水印与过滤器文本框——这不是为了美观,而是倒逼验证闭环。下面是我现在带学生必做的三步验证法,已固化为checklist.md模板:
6.1 编译层验证:确保源码在目标环境零报错
不满足于g++ -o a.out *.cpp能运行,必须检查:
- 符号表完整性:
nm a.out | grep "U "输出为空(U表示undefined symbol); - 动态库依赖:
ldd a.out显示所有库路径有效(尤其libpcap.so在Ubuntu 22.04需sudo apt install libpcap-dev); - 内存安全:用
valgrind --leak-check=full ./a.out运行10秒,确认definitely lost: 0 bytes。
6.2 抓包层验证:Wireshark与源码日志的双向对齐
这是最容易被忽略的环节。以实验1的app.js为例:
- 在代码中插入
console.log([PROXY] ${new Date().toISOString()} ${req.method} ${req.url} → ${targetHost}); - Wireshark中导出HTTP流(右键包 → Follow → TCP Stream),保存为
proxy_flow.txt; - 用Python脚本比对时间戳与URL:
# validate_proxy.py import re with open("proxy_flow.txt") as f: flow = f.read() urls = re.findall(r"GET\s+(/.*?)\s+HTTP", flow) # 与console.log中的URL列表逐行比对
6.3 报告层验证:文档结论必须有数据支撑
report.docx中所有结论性语句,如“GBN协议在丢包率15%时吞吐量下降42%”,必须对应gbn_sender.cpp中stats.throughput变量的实时打印,且该打印需在main()循环末尾强制刷新:
printf("Throughput: %.2f KB/s\n", stats.throughput); fflush(stdout); // 关键!否则重定向到文件时内容延迟没有fflush(),report.docx里的性能数据就是空中楼阁。
从那以后我每次带学生做计网实验,都强制走一遍这三步验证:先make clean && make看编译器脸色,再开Wireshark抓包比对日志,最后打开Word文档逐句核对结论来源。不是为了形式主义,而是让学生亲手触摸到“理论→代码→信号→结论”的完整物理链路——当ipv4.cpp发出的字节流真正在网线里变成光信号,当school.pkt里红灯变绿的瞬间,抽象的协议才有了温度。希望帮到你。
本文还有配套的精品资源,点击获取