ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

基于Python实现可靠数据传输协议:从停等到滑动窗口的完整课设指南

基于Python实现可靠数据传输协议:从停等到滑动窗口的完整课设指南

简介:这是计算机网络课程设计场景下的一份Python实现资源包,围绕UDP设计可靠数据传输协议,完整覆盖停等协议、GBN和SR的改进思路。内容对应实验要求,包括单向可靠传输、丢包模拟、双向数据传输以及基于协议的C/S文件传输应用,适合正在学习网络原理或需要完成课程设计参考的读者。压缩包共14个文件,约723KB,以8个Python源文件为核心,配合txt数据文件、docx实验报告、README说明和License文件,既有可运行的server与client源码,也有配置工具和数据样本。已有596人学习下载,作者s1t16按实验步骤组织文件,便于从基础停等协议逐级扩展到GBN与SR。参考README和报告,可快速理解协议状态机、滑动窗口与丢包重传机制,也可将其中的UDP可靠性扩展思路迁移到文件传输场景,适合实践入门或二次开发。

1. 从 UDP 不可靠说起:这门课设到底要你交出什么

很多同学拿到“基于 Python 实现可靠数据传输协议”这个题目,第一反应是“直接用 TCP 不就行了”。但如果真这么做,课程设计基本就翻车了。题目要求的是基于 UDP 设计并实现停等协议、GBN 协议,再演进到 SR 协议,整个实验的核心不是“传数据”,而是让你在 UDP 这种不可靠、不保序、无拥塞控制的信道上,通过协议机制去解决丢包、重复、乱序的问题。换句话说,你需要亲手写出一套“迷你 TCP”,这才是这份资源真正的价值所在。

这份编号为 100010493 的课程设计资源,覆盖了从停等协议到 GBN、再到 SR 的完整演进链路,并且包含服务器到客户端的单向传输、双向数据传输模拟、基于停等协议的 C/S 文件传输应用等全部实验内容。它的设计目标很明确:让你从零开始理解可靠数据传输的基本原理,掌握滑动窗口协议的工作原理,并且能直接用 Python 代码验证自己的思路。无论你是计算机网络课程需要交课设报告,还是想深入理解 TCP 可靠传输背后的设计哲学,这套方案都能作为你直接参考甚至照搬的完整蓝本。

接下来我会按照实际做项目的顺序,从总体设计、模块实现、避坑指南到最终验收,把这份资源里的关键技术点和工程实现细节全部拆给你看。

2. 总体架构设计:协议分层与四个核心模块的职责划分

做网络协议这类项目,最忌讳一上来就写代码。我一般会先把架构图在脑子里画清楚:数据从服务器端产生,经过协议层封装,通过 UDP Socket 发送,再在客户端经过对应的协议层解封装,最后交给应用层处理。这份资源里的源码组织方式非常标准,适合直接作为课设报告中的“系统设计”章节素材。

2.1 工程文件结构与启动入口解析

拿到压缩包后,首先需要读懂它的目录结构,这决定了你能否快速跑通整个项目。标准的资源解压后通常是这样的结构:

datatransferprotocol/ ├── src/ │ ├── protocol/ │ │ ├── __init__.py │ │ ├── server.py │ │ ├── client.py │ │ └── util.py │ ├── config.py │ └── data/ │ ├── client_data.txt │ └── server_data.txt ├── recv/ │ └── client_recv.txt ├── report.docx ├── README.md └── LICENSE

这个结构划分非常清晰。src/protocol/下是协议栈的核心实现,其中server.py负责发送端逻辑,client.py负责接收端逻辑,util.py通常封装了校验和计算、数据包序列化等公共工具函数。config.py是全局配置项,比如 IP 地址、端口号、窗口大小、超时重传时间等参数都定义在这里。data/目录存放测试数据文件,recv/目录存放客户端接收到的数据。整体是标准的 C/S 架构,非常适合作为计算机网络课程设计的演示项目。

2.2 数据包格式设计与序列化方法

可靠传输协议的基石是数据包的格式设计,这和 HTTP 协议头、TCP 报文段格式是一样的道理。在这个项目里,每个数据包都必须包含几个关键字段:序列号(Sequence Number)、确认号(Acknowledgment Number)、校验和(Checksum)、数据长度(Length)以及实际数据负载。用 Python 实现时,struct模块是处理二进制序列化最方便的工具。

import struct # 数据包格式: [序列号(4字节) | 确认号(4字节) | 校验和(2字节) | 长度(2字节) | 载荷] PACKET_HEADER_FORMAT = "!IIHH" HEADER_SIZE = struct.calcsize(PACKET_HEADER_FORMAT) MAX_PAYLOAD_SIZE = 1024 # 最大载荷 1KB def make_packet(seq_num: int, ack_num: int, payload: bytes = b"") -> bytes: length = len(payload) # 计算校验和: 先将头部和载荷拼在一起,对每个16位字求和 header_no_checksum = struct.pack(PACKET_HEADER_FORMAT, seq_num, ack_num, 0, length) checksum = compute_checksum(header_no_checksum + payload) header = struct.pack(PACKET_HEADER_FORMAT, seq_num, ack_num, checksum, length) return header + payload def parse_packet(packet: bytes): header = packet[:HEADER_SIZE] seq_num, ack_num, checksum, length = struct.unpack(PACKET_HEADER_FORMAT, header) payload = packet[HEADER_SIZE:HEADER_SIZE + length] return { "seq_num": seq_num, "ack_num": ack_num, "checksum": checksum, "length": length, "payload": payload, }

注意这里的校验和计算,类似 TCP 的校验和算法,将整个数据包(包括头部和载荷)按 16 位一组进行反码求和。接收端收到数据包后重新计算校验和,如果与包内携带的校验和不一致,就说明数据在传输过程中被破坏了,必须丢弃并请求重传。使用"!IIHH"格式化串表示使用网络字节序(大端序),避免不同主机架构间的字节序问题。

2.3 滑动窗口协议的状态变量设计与职责边界

从停等协议演进到 GBN 协议,核心在于引入滑动窗口,窗口大小决定了信道利用率。停等协议的利用率太低了,发一个包等一个确认,往返时间(RTT)内发送方完全空闲。如果链路带宽高、延迟大,停等协议的信道利用率会趋近于零。GBN 协议通过允许发送方连续发送多个未被确认的分组,把窗口“滑”起来,从而大幅度提升吞吐量。

在这份资源的 GBN 实现中,发送端需要维护以下状态变量:base(窗口基序号)、next_seq_num(下一个要发送的序号)、window_size(窗口大小)、timer(计时器)。接收端则维护expected_seq_num(期望接收到的序号)。整体设计上,protocol/server.py负责发送窗口管理和超时重传逻辑,protocol/client.py负责接收端的累积确认和丢包检测逻辑,两个模块通过 UDP Socket 通信,职责边界非常清晰。

3. 协议演进实现:从停等机制到滑动窗口的工作原理

中间这章是整个课设的核心和价值所在。你需要向答辩老师展示的不仅是能跑通的代码,更是你对这几种协议机制差异的深刻理解。

3.1 停等协议设计:超时重传与确认机制

停等协议是最基础的可*靠数据传输协议,原理非常简单:发送方发送一个分组后,必须等待接收方返回确认(ACK),收到确认后才能发送下一个分组。如果发送方在超时时间内没有收到 ACK,就重传该分组。

def stop_and_wait_send(sock, dest_addr, payload, timeout=2.0): packet = make_packet(seq_num=0, ack_num=0, payload=payload) while True: sock.sendto(packet, dest_addr) sock.settimeout(timeout) try: response, _ = sock.recvfrom(HEADER_SIZE) ack_packet = parse_packet(response) if ack_packet["ack_num"] == 0: print(f"[发送端] 收到对 seq=0 的确认,发送完成") return True except socket.timeout: # 血泪经验:超时后必须重新发送,并且要重新设置计时器 print(f"[发送端] 超时未收到ACK,重传 seq=0") continue

这个实现里的关键点有两个。第一个是超时重传,很多同学在这里踩坑:单程超时时间设置得太短,导致频繁重传;设置得太长,又会大幅降低传输效率。我一般建议超时时间设置为略大于往返时间的两倍。第二个是 ACK 确认号的设计,停等协议中确认号的含义是“我已经正确收到序号为 N 的数据包,下一个期望收到的是 N+1”。

3.2 累积确认、超时重传与窗口滑动

把停等协议的等待时间“填满”,就得到了 GBN 协议的核心机制:发送窗口。发送方维护一个窗口,窗口内所有分组都可以连续发送而不用等待各自的 ACK。接收方只按序接收,一旦收到乱序分组就直接丢弃,并对最后一个按序接收到的分组发送累积确认。

GBN 发送端的核心逻辑是判断哪些分组可以发送,哪些分组必须等 ACK:

def gbn_send(sock, dest_addr, data_packets): """按 GBN 协议发送一组数据包。 :param data_packets: 已按序号排好的数据包列表 """ window_size = config.WINDOW_SIZE base = 0 # 窗口起始序号(绝对序号) next_seq_num = 0 # 下一个待发送的序号 total_packets = len(data_packets) while base < total_packets: # 发送窗口还没满,且还有包可发,就继续发包 while next_seq_num < base + window_size and next_seq_num < total_packets: sock.sendto(data_packets[next_seq_num], dest_addr) print(f"[发送端] 发送 seq={next_seq_num}") next_seq_num += 1 # 启动一个计时窗口,等待累积确认 sock.settimeout(config.TIMEOUT) try: response, _ = sock.recvfrom(MAX_PACKET_SIZE) ack_packet = parse_packet(response) # 累积确认:收到对 n 的确认,意味着前面 n 个包全部正确到达 new_base = ack_packet["ack_num"] + 1 if new_base > base: print(f"[发送端] 收到累积确认 ACK={ack_packet['ack_num']},窗口滑到 {new_base}") base = new_base except socket.timeout: # 超时:从 base 开始重传整个窗口 print(f"[发送端] 超时,从 seq={base} 开始重传整个窗口") next_seq_num = base continue

这里最容易理解错的是累积确认。比如接收方已经按序接收了 0、1、2,那么发送 ACK 中的确认号为 2,表示“0~2 全部收到,请发 3”。如果发送方收到 ACK=2,窗口基序号直接变成 3,窗口向前滑动 3 个位置。如果第三个包丢失了,接收方收到第四个包时发现序号不连续,会直接丢弃,并重复发送 ACK=2,发送方重复收到同一个 ACK,达到一定次数后触发快速重传或超时重传。

3.3 GBN 改进为 SR 协议:接收窗口与选择重传

GBN 协议的致命缺点是单个丢包会导致大量重传。比如窗口大小是 16,第 4 个包丢了,接收方会丢弃所有后续按序到达的包,发送方超时后必须重传 5~16 号包。在误码率高的信道上,这种“回退 N”策略的吞吐量会受到明显影响。

SR(选择性重传)协议就是针对这个问题做的优化。SR 不仅为发送方提供滑动窗口,也为接收方提供滑动窗口缓存机制。接收方不再丢弃乱序到达的分组,而是先缓存起来,等缺失的分组到达后再一起按序交付给上层。

def sr_receive(sock, base, window_size, buffer_dict): """SR 接收端处理逻辑。 :param buffer_dict: 序号->包内容的缓存字典 """ while True: packet_data, addr = sock.recvfrom(MAX_PACKET_SIZE) pkt = parse_packet(packet_data) seq = pkt["seq_num"] # 接收窗口范围判定 if base <= seq < base + window_size: buffer_dict[seq] = pkt # 先缓存起来存着 # 移动窗口:如果当前 base 指向的数据已经到达,就持续前移 while base in buffer_dict: # 将缓存中的数据按序交付给上层应用 deliver_to_app(buffer_dict[base]["payload"]) del buffer_dict[base] base += 1 send_ack(seq) # 对已收到的包确认,注意这里是选择确认 elif seq < base: # 说明这个包是重复的旧包,接收方已经滑过去了,但还是得再发一次ACK send_ack(seq)

SR 与 GBN 的差异在实现中非常关键。GBN 的 ACK 是“累积”的,SR 的 ACK 是“选择”的。SR 接收端需要为没有到达的分组设置定时器(或者在发送端单独计时重传每个超时分组的 ACK)。从代码量来看,SR 的实现复杂度比 GBN 高许多。这也是实验内容的最后一个进阶步骤:将所设计的 GBN 协议改进为 SR 协议。如果你做到这一步,说明你已经完全掌握了滑动窗口协议的精髓,完全可以作为课设报告里的“创新点”来写。

4. 工程落地实现:单向传输、双向传输与文件传输应用

协议机制的代码是骨架,工程落地则是血肉。课设要求里明确提到了三个必须实现的场景:单向可靠数据传输、模拟数据包丢失验证协议有效性、双向数据传输,以及一个 C/S 结构的文件传输应用。

4.1 基于 UDP 的单向可靠传输测试链路

先从最基本的单向传输链路说起。服务器端按顺序读取文本数据,切分成固定大小的数据块,用 GBN 协议发送给客户端;客户端接收后重组数据,写回本地文件。整个链路的测试步骤如下:

  • 先跑通“无丢包”场景:修改config.py中的丢包率配置为 0,验证基础传输功能是否正常。
  • 再跑通“模拟丢包”场景:把丢包率设为 10%~30%,观察协议在随机丢包环境下是否仍能保证数据完整交付。

模拟丢包时,注意util.py里通常有一个随机数丢失判断。这个判断会直接改变实验结果:

def should_drop_packet(drop_rate: float = 0.0) -> bool: """按丢包率决定是否丢弃当前数据包""" return random.random() < drop_rate def udt_send(sock, packet, dest_addr, drop_rate=0.0): """不可靠信道传输,按概率丢包""" if should_drop_packet(drop_rate): print(f"[信道] 数据包 seq={parse_packet(packet)['seq_num']} 在传输中丢失...") return sock.sendto(packet, dest_addr)

一定要理解这段代码的位置关系。丢包模拟发生在“发送端调用 sendto 之前”,模拟的是数据在网络上传输时被路由器丢弃的过程。实际实验中可以通过打印日志对比相同序号数据包的出现次数,来证明重传机制确实触发了。这也是报告里“实验结果与分析”部分的关键截图依据。

4.2 双向数据传输的实现方式与冲突避免

很多同学在把单向传输改成双向传输时犯了难。双向传输并不是简单地开两个 Socket 各收各的,而是要在一个事件循环里同时处理“发送数据”和“接收确认”两条逻辑流。如果处理不当,就会出现死锁:双方都在等对方的 ACK,但双方的 ACK 都发送不出去。

实现双向传输,我一般会采用单 Socket + 状态切换的策略:把收发逻辑合并到同一个循环里,在每个循环周期内先检查有没有需要重传的超时分组,再尝试接收对端的数据和确认,最后发送新数据。通过 socketselect或设置settimeout来避免阻塞:

def bidirectional_send_receive(sock, dest_addr, local_data): """在同一线程内交替处理发送和接收,避免双向传输死锁""" base = 0 next_seq_num = 0 while base < len(local_data) or has_received_data: # 先从窗口里往外发数据 while next_seq_num < base + config.WINDOW_SIZE and next_seq_num < len(local_data): sock.sendto(make_packet(next_seq_num, 0, local_data[next_seq_num]), dest_addr) next_seq_num += 1 # 再尝试接收对方的数据/确认 sock.settimeout(0.5) # 非阻塞式检查,停顿 500ms try: packet = sock.recvfrom(MAX_PACKET_SIZE)[0] handle_packet_type(packet) # 根据类型分发到数据/确认处理逻辑 except socket.timeout: pass # 处理下一批数据 # 最后检查是否超时需要重传 if timer_expired(): next_seq_num = base

这里有个非常实用的细节:如果两端的发送节奏不是对等的,比如服务器要发大文件而客户端只返回少量确认,那么客户端的发送缓冲区会很快清空。此时客户端不能退出循环,必须继续处理接收到的数据包并发送 ACK。正确做法是客户端在自己的循环里等到“收到服务器的传输结束标志”或“超时退出”后再关闭 Socket。这是课设答辩时老师最喜欢追问的细节之一。

4.3 基于停等协议的 C/S 文件传输应用实现

文件传输应用是停等协议最直观的应用场景。实现逻辑是服务器读取文件内容、按 chunk 分割、加序号封装成包,客户端收包后按序号重组并写入新文件。这个场景和纯文本传输的区别在于它必须考虑到大文件的处理效率和异常恢复能力。

def send_file(sock, file_path, dest_addr, chunk_size=1024): """基于停等协议发送文件 :return: 成功发送的字节数 """ seq = 0 total_bytes = 0 with open(file_path, "rb") as f: while True: chunk = f.read(chunk_size) if not chunk: break packet = make_packet(seq_num=seq, ack_num=0, payload=chunk) stop_and_wait_send(sock, dest_addr, packet) seq += 1 total_bytes += len(chunk) print(f"[文件传输] 完成,共发送 {seq} 个数据包,{total_bytes} 字节") return total_bytes

文件传输的实现要注意几个问题。每次只发送 1024 字节,如果文件有几十 MB,就需要发送几万个数据包,停等协议的效率会非常低。这也是为什么课设要求里先做停等协议的文件传输,再在 GBN 基础上做同样的文件传输时,你会明显感受到性能差异:GBN 的吞吐量可能是停等协议的几十倍甚至上百倍。这个对比数据写到课设报告的“实验结果分析”里,是非常有说服力的论据。

5. 避坑指南:协议实现中五个最容易翻车的故障排查

计算机网络课设的调试过程往往是玄学般的体验。代码写好了、网络配置也对,但数据就是传不过去。基于这份资源里协议的实现经验,我整理了五个高频故障点,按照现象、原因、解决的思路来排查,能帮你少走很多弯路。

5.1 重传日志打了一堆,但接收端还是收不全数据

  • 现象:服务器端疯狂打印“超时重传”日志,客户端却始终只能收到前几个数据包,后面全部丢失。
  • 原因:这是典型的“发送窗口推进”逻辑错误。在很多初版 GBN 实现里,发送方在超时后直接把next_seq_num重置为base,但此时窗口内可能还有之前未发送完的数据包。如果重传后没有正确更新base,窗口就永远滑不动,形成死循环。
  • 解决:逐行检查窗口滑动的状态转移。在超时重传后,必须重新发送从base到next_seq_num的所有数据包,并且每次收到 ACK 后,base的更新逻辑必须严格等于“ACK序号 + 1”。我建议在每次状态变化时打印一行包含base、next_seq_num、window_size的日志,辅助判断问题所在。

5.2 接收端收到的数据完整但顺序错乱,文件打不开

  • 现象:客户端收到的数据量是对的,但重组后的文件与原始文件不一致,或者图片文件直接无法打开。
  • 原因:数据包乱序。UDP 本身不保证数据包的到达顺序,虽然 GBN 接收端会丢弃乱序包,但如果你错误地实现了“直接收下所有包”的逻辑,就会出现乱序交付。
  • 解决:检查接收端是否严格按“期望序号”进行过滤。GBN 接收端唯一的合法交付依据是if seq_num == expected_seq_num:,只有序号完全匹配才接收并交付上层,否则直接丢弃。SR 接收端允许缓存乱序包,但在交付给应用层时也必须按缓存中的序号从小到大依次交付,序号中间有空洞时绝不能提前交付后面的包。

5.3 开启模拟丢包后,程序运行了几分钟还没有结束

  • 现象:丢包率设置为 20% 后,程序就像卡死了一样,日志长时间不更新。
  • 原因:不是程序死锁,而是超时时间设置太长。假设你的 RTT 是 100ms,但超时时间设了 10 秒。每遇到一个丢包,发送方就要干等 10 秒才重传,传输效率断崖式下降。
  • 解决:把超时时间调到理论 RTT 的两倍左右。在局域网环境中,一般 0.5~1 秒足够充分。如果不知道网络 RTT,可以先用ping命令粗测,再在config.py里动态配置。更高级的做法是实现自适应重传:根据最近的 RTT 样本计算加权平均 RTT 和偏差,设置动态超时时间,这也是报告里可以展开写的优化点。

5.4 双向传输时两边都在等 ACK,程序死锁

  • 现象:开启双向传输功能后,程序要么直接卡死,要么等待很长时间后才开始传输。
  • 原因:这是典型的“全双工通信中的死锁问题”。如果发送方在等待 ACK 时使用阻塞式recvfrom,且接收方也在等待对方的数据才发送 ACK(比如双方都尝试先发送数据再接收),就会形成循环等待。
  • 解决:采用事件循环或select机制处理 Socket。在等待超时时间内同时监听“可读事件”和“可写事件”,有数据可读就先读,有 ACK 需要确认就先处理 ACK。关注点转移:把“发送-等待”的线性模型改成“发送-监听-处理”的并发模型,这是工程实现里非常重要的思维转变。

5.5 校验和算不对,接收端把所有包都视为损坏

  • 现象:接收端报错,丢弃所有数据包。调试发现,明明在同一个机器上收发,校验和计算方式没有问题,但解析出的数据和发送前不一致。
  • 原因:字节序问题或者是没把校验和字段本身置零。计算校验和时,头部中的checksum字段必须为 0,计算完再填入;接收端解析时要先取校验和字段,将它置为 0 后重新计算整体校验和,与取出值比较。
  • 解决:严格顺序是“置零 → 拼接 → 计算 → 填充;收到时 = 取校验和 → 置零 → 拼接 → 重算 → 对比”。此外,如果是在 Windows 和 Linux 主机间跨平台传输,要注意 sockaddr 结构和字节序的差异。

6. 验收与答辩准备:如何把实验结果讲清楚、拿高分

做课程设计最后一步就是写报告和现场演示了。很多同学程序能跑,但讲不清楚原理,答辩时被老师追问几句就答不上来,白白丢了分。这一章我重点讲验收的方法论和答辩时的准备策略。

6.1 制定可量化的验收标准清单

验收之前,先明确“什么算完成,什么算优秀”。我会建议你用下面这个表格来逐项自查:

验收项合格标准优秀标准
停等协议在无丢包网络下能正确传输 1KB 文本,接收端数据与发送端一致在 10% 丢包率下仍能正确传输,且日志清晰展示重传过程
GBN 协议在模拟丢包环境下传输数据,保证 100% 完整性用两组不同丢包率(如 5% 和 30%)做对比实验,计算出信道利用率的变化趋势
双向数据传输两个方向的数据都能正确到达对方双方同时发送大数据量时不会死锁,传输完毕后正确关闭连接
文件传输应用传输一个 1MB 文件,MD5 校验一致对比停等协议和 GBN 协议传输同一文件的总耗时,给出统计图表
SR 协议改进能正确实现选择重传,乱序到达的分组能被缓存并最终按序交付与 GBN 协议在相同丢包率下对比“重传数据包数量”,SR 明显小于 GBN

把这张表里的每一项都实际跑通一遍,你的报告里的“实验结果”章节就有血有肉了。

6.2 答辩演示脚本的编排技巧

答辩的现场演示时间是有限的,通常只有 5~10 分钟。不要现场去敲代码或临时改配置。提前准备一个 5 分钟的演示脚本,强烈建议按以下流程编排:

  • 第一步,先花半分钟展示项目结构,快速过一眼代码组织,证明这是你的自主实现。
  • 第二步,启动停等协议传输一个文本文件,全程无丢包,速度很慢,展示成功结果。
  • 第三步,开启 20% 丢包率,展示协议重传流程和接收结果。
  • 第四步,启动 GBN 协议传输大文件,展示窗口滑动的高吞吐量,对比第二步明显提速。
  • 第五步,展示 SR 协议的重传统计,对比 GBN 的重传数量,说明自己理解了改进动机。

演示中最容易翻车的点是“开着丢包率但程序崩溃了”。为了保险起见,我会把丢包率和丢包种子(随机种子)配置成可复现的固定值,确保演示过程每次都能重现相同的结果,而不是依赖于不可控的随机数。

6.3 答辩追问环节的应答框架与经验教训

答辩老师几乎必问的几个问题,我帮你把答法提前准备好。第一个问题,为什么信道不可靠但还要基于 UDP 设计可靠协议?回答核心是:TCP 的可靠传输是在内核协议栈里的,看不到隐藏的实现细节;基于 UDP 自己实现,能理解和控制每一个机制,这才是协议设计的本质。第二个问题,GBN 为什么叫回退 N,回退的是哪 N 个?你要能画出时序图,指出丢失的包 N 以及其后的所有数据包都需要重传。第三个问题,SR 协议是怎么减少无效重传的?答案是接收端缓存窗口 + 发送端单独定时器。

关于资源里的代码如何避免被质疑雷同,我有个实际的经验:不要原封不动地提交代码。哪怕只改动一些变量命名、增加注释、调整函数拆分的粒度,都能体现你对代码的理解。更推荐的做法是基于资源里的框架,自己重新实现一遍核心的窗口管理逻辑,遇到问题再来对照参考源码。从那以后,我每次做协议类项目,都会给自己定一条规矩:交给验收的东西一定是在我脑子里完整过过一遍流程的,能画得出时序图,能解释得清状态变化,绝不交一份“能跑但讲不明白”的代码上去。课设和真实项目都是一样,能清晰表达出来的设计才算真正掌握。

希望这份基于 Python 实现可靠数据传输协议的完整拆解,能帮你在课程设计和毕业设计中少踩几个坑。祝做出一个能让你站上讲台自信讲演的优秀作品。

本文还有配套的精品资源,点击获取

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进