简介这份资源是哈尔滨工业大学计算机网络课程实验1至6的完整报告与配套源码合集面向正在修读计算机网络实验课的高校学生以及希望动手理解协议实现细节的自学者。内容覆盖HTTP代理服务器的设计与实现、HTTP分组收发与转发、可靠数据传输GBN协议的设计与实现、利用Wireshark进行协议分析以及简单网络组建与配置等六个实验基本对应课程从应用层到传输层的核心知识点。压缩包共22个文件约4.67MB包含6份docx实验报告、3个cpp源码文件、7个js脚本、2个json配置、2个md说明文档以及1个pkt拓扑文件报告与代码相互对应便于对照阅读。目前已有562人学习下载。读者可借助其中的源码理解代理服务器与GBN协议的实现思路结合Wireshark抓包文件与网络拓扑完成协议分析并通过实验报告梳理实验步骤、结果验证与排错过程适合作为课程实验参考与期末复习材料。1. 哈工大计算机网络实验 1-6一份 .rar 里到底装了什么如果你正在搜「哈工大计算机网络实验1-6实验报告及源码.rar」大概率是三种处境之一实验课设卡在某个 socket 编程上跑不通、要交报告但不知道抓包数据怎么分析、或者想提前把六个实验的代码框架过一遍心里有底。这个压缩包对应的是哈工大计算机网络课程配套的六个递进式实验通常覆盖物理层/数据链路层的编码与 CRC 校验、网络层的 IP 分片与路由、传输层的 UDP/TCP socket 编程、应用层的 HTTP 与 DNS 抓包分析这几条主线。它解决的不是「计算机网络是什么」这种概念问题而是「协议怎么用代码实现、报文怎么在真实链路上跑起来」的动手问题。适合正在上这门课的学生、准备考研复试要手写协议栈的考生以及想补网络编程实操的初级后端。下面我按「先跑通、再讲透、最后避坑」的顺序把六个实验的复现路径拆开讲。2. 实验环境搭建与六个实验的依赖关系2.1 为什么建议用 Linux 虚拟机而不是 Windows 直接跑六个实验里抓包类实验HTTP、DNS在 Windows 上用 Wireshark 也能做但涉及原始套接字raw socket、自定义以太网帧收发、IP 分片重组这几个实验时Windows 的 Winsock 对 raw socket 限制很多需要管理员权限且部分协议头无法自定义。我一般直接开一台 Ubuntu 20.04 或 22.04 的虚拟机网络模式选桥接这样抓包能看到真实网关流量而不是 NAT 下的虚拟网段。虚拟机配置 2 核 4G 足够实验本身不吃资源吃的是你对抓包工具和 socket API 的熟悉度。装环境时按实验类型分两批装依赖。抓包分析类需要 Wireshark 和 tcpdumpsocket 编程类需要 gcc、make、python3 以及可选的 libpcap-dev。一条命令把基础工具装齐sudo apt update sudo apt install -y build-essential gcc make python3 python3-pip \ tcpdump wireshark libpcap-dev net-tools # 把当前用户加入 wireshark 组避免每次抓包都要 sudo sudo usermod -aG wireshark $USER装完后要重新登录一次让用户组生效否则 Wireshark 仍然提示权限不足。libpcap-dev是给 C 语言抓包实验用的如果你只做 Python 版可以跳过。net-tools提供ifconfig和netstat新版 Ubuntu 默认用ip命令但很多实验指导书里写的还是ifconfig装上省得对不上。2.2 六个实验的先后依赖别跳着做这六个实验不是并列关系有明确的依赖链。实验 1通常是以太网帧封装与 CRC 校验和实验 2IP 分片与重组是底层基础实验 3UDP socket 编程和实验 4TCP socket 编程依赖你对端口、字节序、报文结构的理解实验 5HTTP 协议分析和实验 6DNS 协议分析则是应用层抓包需要前面抓包工具已经用熟。如果你时间紧建议按 1→2→3→4→5→6 顺序做跳做的话至少先把实验 1 的抓包环境跑通不然后面 Wireshark 过滤器都不会写。实验序号典型主题核心工具预估耗时实验 1以太网帧与 CRC 校验Wireshark、Python/C2-3 小时实验 2IP 分片与重组Wireshark、Python3-4 小时实验 3UDP socket 编程Python socket / C2-3 小时实验 4TCP socket 编程Python socket / C3-4 小时实验 5HTTP 协议抓包分析Wireshark、curl2 小时实验 6DNS 协议抓包分析Wireshark、nslookup/dig2 小时耗时是按「第一次做、边查边写」估的熟手可能减半。实验 2 和实验 4 最容易超时因为分片重组和 TCP 状态机的手动构造容易出错。2.3 源码目录怎么组织报告和代码怎么对应拿到 .rar 解压后常见结构是每个实验一个文件夹里面混着源码、抓包文件.pcapng和报告模板。我建议你重新整理成下面这种结构报告里引用代码行号时不会乱mkdir -p netlab/{lab1_frame,lab2_ipfrag,lab3_udp,lab4_tcp,lab5_http,lab6_dns} # 每个实验目录下再分 src/ 和 capture/ 和 report/ cd netlab/lab1_frame mkdir src capture report这样做的实际好处是报告里写「见 src/crc.py 第 23 行」时路径清晰抓包文件按实验分开存答辩或复查时不用满硬盘找。源码文件命名带上实验编号比如lab3_udp_server.py、lab3_udp_client.py避免六个实验的server.py互相覆盖。3. 实验 1-2帧封装、CRC 校验与 IP 分片怎么动手3.1 以太网帧手工构造与 CRC 校验的代码实现实验 1 的核心是让你理解一个以太网帧从目的 MAC、源 MAC、类型字段到数据、FCS 的完整结构并亲手算一次 CRC。很多同学卡在 CRC 上因为课本讲的是模 2 除法但代码实现用的是查表法或位移法两者结果要一致。下面是一个可直接跑的 Python 实现用位移法算 CRC32以太网 FCS 用的就是 CRC32多项式 0x04C11DB7 的反转形式# lab1_frame/crc.py def crc32_ethernet(data: bytes) - int: 计算以太网 FCS 使用的 CRC32返回 32 位整数 crc 0xFFFFFFFF poly 0xEDB88320 # 0x04C11DB7 的位反转形式 for byte in data: crc ^ byte for _ in range(8): if crc 1: crc (crc 1) ^ poly else: crc 1 return crc ^ 0xFFFFFFFF if __name__ __main__: # 构造一个最小以太网帧头 数据不含 FCS dst_mac bytes.fromhex(ffffffffffff) # 广播 src_mac bytes.fromhex(001122334455) ethertype bytes.fromhex(0800) # IPv4 payload bhello_netlab frame dst_mac src_mac ethertype payload fcs crc32_ethernet(frame) print(fFCS 0x{fcs:08X})这段代码的关键在poly 0xEDB88320它和课本上的0x04C11DB7是位反转关系因为以太网在链路上是低位先发。如果你用课本多项式直接算结果会和 Wireshark 抓到的 FCS 对不上这是最常见的翻车点。参数上crc初值取0xFFFFFFFF、最后再异或0xFFFFFFFF这是标准 CRC32 的约定少一步结果就错。验证方法用 Wireshark 抓一个真实帧看它显示的 FCS 值需要在 Wireshark 里开启「假设 FCS 存在」选项和你算的对比。3.2 IP 分片与重组偏移量、标志位怎么设实验 2 要求你构造一个超过 MTU通常 1500 字节的 IP 数据报手动分片再用抓包验证。分片的关键字段是 16 位标识Identification、3 位标志Flags其中 MF 表示还有更多分片、13 位片偏移Fragment Offset单位是 8 字节。下面这段代码演示如何把一个 4000 字节的 payload 按 1480 字节分片# lab2_ipfrag/fragment.py import struct def make_fragments(payload: bytes, mtu_payload: int 1480): 把 payload 按 mtu_payload 切片返回 (offset, mf, data) 列表 frags [] offset 0 total len(payload) while offset total: chunk payload[offset:offset mtu_payload] # 片偏移以 8 字节为单位所以必须是 8 的倍数 frag_offset offset // 8 mf 1 if offset len(chunk) total else 0 frags.append((frag_offset, mf, chunk)) offset len(chunk) return frags if __name__ __main__: payload bA * 4000 for i, (off, mf, data) in enumerate(make_fragments(payload)): print(f分片{i}: offset{off} MF{mf} len{len(data)})这里最容易错的是片偏移的单位。offset是字节数但写进 IP 头时要除以 8因为片偏移字段只有 13 位用 8 字节做单位才能表示最大 65535 字节。如果你直接写字节数偏移字段会溢出重组端拼出来的数据就是乱的。另一个坑是最后一个分片的 MF 必须为 0中间分片为 1代码里用offset len(chunk) total判断边界情况payload 正好是 mtu_payload 整数倍要单独测一下否则最后一个分片会多出一个空片。3.3 用 Wireshark 过滤器验证分片结果构造完分片后要抓包验证。Wireshark 的显示过滤器写ip.flags.mf 1能筛出所有还有后续分片的包写ip.frag_offset 0能筛出首片。重组验证看 Wireshark 的「Reassembled IPv4」提示如果它能把你的分片拼回 4000 字节说明偏移和标志位都对了。抓包时建议先ping一个大包触发系统分片对比你自己构造的分片和系统分片的字段差异这是最快的对照学习方式。4. 实验 3-4UDP 与 TCP socket 编程的落地细节4.1 UDP 回显服务器字节序和 recvfrom 的坑实验 3 通常要求写一个 UDP 回显服务器和客户端。UDP 无连接代码短但字节序和缓冲区大小两个坑几乎人人踩。下面是一个能直接跑的 Python 版本# lab3_udp/udp_echo_server.py import socket HOST, PORT 0.0.0.0, 9999 sock socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.bind((HOST, PORT)) print(fUDP 服务器监听 {HOST}:{PORT}) while True: data, addr sock.recvfrom(2048) # 缓冲区给足UDP 一次收一个完整报文 print(f收到来自 {addr} 的 {len(data)} 字节) sock.sendto(data, addr) # 原样回显recvfrom(2048)的 2048 是单次接收缓冲区大小UDP 是面向报文的如果发送方发的报文超过这个值多出的部分会被丢弃且不报错这是 UDP 的「静默丢包」特性。所以缓冲区要大于你预期的最大报文。bind的地址用0.0.0.0表示监听所有网卡如果你只想本机测试可以写127.0.0.1。客户端那边要注意sendto的目标地址必须是元组(host, port)少写括号或写成字符串都会报类型错误。4.2 TCP 并发服务器多线程还是 select实验 4 的 TCP 服务器要求支持多客户端。两种常见做法多线程每个连接一个线程和 I/O 多路复用select/poll/epoll。课程实验一般用多线程就够代码直观。下面是一个多线程 TCP 回显服务器# lab4_tcp/tcp_echo_server.py import socket import threading def handle_client(conn, addr): print(f新连接 {addr}) try: while True: data conn.recv(1024) if not data: # 客户端关闭连接 break conn.sendall(data) finally: conn.close() print(f连接 {addr} 关闭) HOST, PORT 0.0.0.0, 8888 server socket.socket(socket.AF_INET, socket.SOCK_STREAM) server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # 避免 TIME_WAIT 占用端口 server.bind((HOST, PORT)) server.listen(5) print(fTCP 服务器监听 {HOST}:{PORT}) while True: conn, addr server.accept() t threading.Thread(targethandle_client, args(conn, addr), daemonTrue) t.start()SO_REUSEADDR这行是血泪经验不加的话服务器重启时如果上一个连接处于 TIME_WAIT 状态bind会报「Address already in use」你得等 2 分钟才能再启动。listen(5)的参数是半连接队列长度实验环境 5 够用生产环境要调大。daemonTrue让线程随主进程退出避免 CtrlC 后线程还挂着。TCP 的recv返回空字节b表示对端关闭这是判断连接结束的标准方式不要用异常来判断。4.3 用 tcpdump 抓 socket 通信验证三次握手写完 socket 代码后用 tcpdump 抓本地回环验证握手过程# 抓 lo 接口上 8888 端口的包-S 显示绝对序列号 sudo tcpdump -i lo -S port 8888 -w lab4_tcp/capture/tcp_handshake.pcap然后启动服务器和客户端抓完后用 Wireshark 打开你应该能看到 SYN、SYN-ACK、ACK 三个包以及后续的数据传输和 FIN 挥手。重点看序列号和确认号的变化这是理解 TCP 可靠传输最直观的方式。如果抓不到包先确认 tcpdump 抓的是lo还是eth0本机测试走回环跨机测试走网卡抓错接口是新手最常见的「抓不到包」原因。5. 实验 5-6HTTP 与 DNS 抓包分析的排查与避坑5.1 HTTP 抓包为什么你只看到加密流量实验 5 要求分析 HTTP 请求响应。但现在大部分网站默认 HTTPS你抓到的全是 TLS 加密流量看不到 HTTP 头和 body。解决办法是找纯 HTTP 的测试站点或者用curl指定 HTTP 协议访问。常见做法是用http://开头的测试接口或者本地起一个简单的 HTTP 服务器# 本地起一个 HTTP 服务器端口 8000 python3 -m http.server 8000 # 另一个终端用 curl 访问强制 HTTP curl -v http://127.0.0.1:8000/curl -v会打印完整的请求头和响应头配合 Wireshark 抓tcp port 8000你能看到 HTTP 报文和 TCP 分段的对应关系。注意 HTTP/1.1 默认开启 keep-alive一个 TCP 连接上可能跑多个请求Wireshark 里要用「Follow HTTP Stream」才能看全。如果实验要求分析真实网站的 HTTP优先选那些还支持 HTTP 的静态资源站别硬啃 HTTPS。5.2 DNS 抓包查询类型和响应码怎么看实验 6 分析 DNS。用dig或nslookup触发查询Wireshark 过滤器写dns。重点看三个字段查询类型A、AAAA、CNAME、MX、响应码NOERROR、NXDOMAIN、以及 TTL。下面命令分别触发 A 记录和 CNAME 查询dig A www.example.com dig CNAME www.example.com # 查询一个不存在的域名观察 NXDOMAIN dig A this-domain-does-not-exist-12345.comWireshark 里展开 DNS 报文Flags字段的Response code为 3 就是 NXDOMAIN。很多同学分不清「查询」和「响应」报文看Flags里的QR位0 是查询1 是响应。DNS 默认走 UDP 53 端口但如果响应超过 512 字节会切到 TCP抓包时过滤器写port 53而不是udp port 53否则会漏掉 TCP 的 DNS 包。5.3 抓包类实验的通用避坑清单现象Wireshark 里看不到任何包。原因没选对网卡或者没开混杂模式。解决抓包前在 Wireshark 首页确认网卡有流量波动虚拟机桥接模式下选eth0而不是lo。现象抓到的包全是 TLS/加密。原因目标站点用了 HTTPS。解决换 HTTP 测试站或本地服务器别在加密流量上浪费时间。现象DNS 查询有请求没响应。原因本机 DNS 缓存命中没真正发查询。解决用dig指定一个不存在的域名或清缓存sudo systemd-resolve --flush-caches。现象tcpdump 抓包文件 Wireshark 打不开。原因tcpdump 写入时权限或磁盘满导致文件截断。解决抓包前确认磁盘空间用-w写文件时加-U让每个包立即刷盘。现象IP 分片实验重组失败。原因片偏移没除以 8或 MF 标志设错。解决回看 3.2 的代码用 Wireshark 的ip.frag_offset字段逐个核对。6. 把六个实验串成一个可复用的网络调试习惯做完这六个实验真正值钱的不是那几份报告而是你养成的抓包和验证习惯。我自己的做法是任何网络问题先抓包别猜。写 socket 代码时先跑通最小回显再加并发和异常处理。CRC 和分片这类底层实验算完一定要用 Wireshark 对照真实报文自己算对了不算对和真实链路一致才算对。进阶一点你可以把实验 3 和实验 4 的服务器改造成一个简单的协议解析器比如在 UDP 回显基础上加一个自定义头部2 字节长度 1 字节类型然后用实验 1 的帧构造思路把它封装成原始套接字发送。这样六个实验就串成了一条线从帧到 IP 到 UDP/TCP 到应用层每一层你都能亲手构造和解析。验证方法很简单写一个 Python 脚本同时起服务器和客户端用assert校验回显数据一致跑通就说明链路没问题。我踩过最深的一个坑是实验 2 的分片代码在本机跑得好好的换到另一台机器就重组失败查了半天发现是对方网卡 MTU 是 1400 而不是 1500分片大小没适配。从那以后我养成了一个习惯任何涉及 MTU 的代码都把 MTU 做成参数不写死。这个习惯后来在真实项目里救过我好几次。希望帮到你。本文还有配套的精品资源点击获取