的FSM状态机,直观理解可靠传输)
用Python模拟RDT协议从rdt1.0到3.0的FSM状态机实战当你第一次学习可靠数据传输协议RDT时是否曾被那些抽象的状态转换图困扰作为计算机网络课程的核心概念RDT协议从1.0到3.0的演进过程实际上是一系列解决实际传输问题的巧妙设计。本文将带你用Python构建一个可视化的RDT协议模拟器通过代码实现发送方和接收方的有限状态机FSM让这些抽象概念变得触手可及。1. 环境准备与基础架构在开始编码前我们需要明确模拟器的核心组件。与单纯阅读理论不同动手实现能让你更直观地理解每个状态转换背后的设计意图。基础组件清单状态机核心用Python类实现发送方和接收方的FSM网络模拟模拟信道特性比特差错、丢包可视化界面实时显示状态转换和分组流动交互控制允许手动触发各种异常场景首先安装必要的Python库pip install matplotlib numpy定义基础状态枚举类from enum import Enum class State(Enum): WAIT_CALL_0 0 # 等待上层调用序号0 WAIT_CALL_1 1 # 等待上层调用序号1 WAIT_ACK_0 2 # 等待ACK序号0 WAIT_ACK_1 3 # 等待ACK序号12. rdt1.0理想信道的实现作为最基础的版本rdt1.0假设信道完全可靠——没有比特差错没有丢包。虽然现实中不存在这样的网络但这是理解协议演进的起点。发送方FSM实现class RDTSender1: def __init__(self): self.state State.WAIT_CALL_0 def rdt_send(self, data): if self.state State.WAIT_CALL_0: packet self.make_pkt(data, 0) self.udt_send(packet) self.state State.WAIT_CALL_1 return True return False # 未就绪 def make_pkt(self, data, seq_num): return {data: data, seq: seq_num} def udt_send(self, packet): print(f[Sender] 发送分组: {packet}) channel.deliver(packet)接收方FSM实现class RDTReceiver1: def __init__(self): self.state State.WAIT_CALL_0 def rdt_rcv(self, packet): if self.state State.WAIT_CALL_0: data self.extract(packet) self.deliver_data(data) self.state State.WAIT_CALL_1 return True return False def extract(self, packet): return packet[data] def deliver_data(self, data): print(f[Receiver] 交付数据: {data})关键观察点单向状态流转0→1→0循环无确认机制假设传输必然成功无差错检测和处理逻辑3. rdt2.0引入比特差错处理现实网络中比特差错不可避免。rdt2.0通过ACK/NAK机制实现差错恢复这是自动重传请求ARQ的最简形式。发送方状态增强class RDTSender2(RDTSender1): def __init__(self): super().__init__() self.current_seq 0 self.saved_packet None def rdt_send(self, data): if self.state in [State.WAIT_CALL_0, State.WAIT_CALL_1]: packet self.make_pkt(data, self.current_seq) self.saved_packet packet # 保存以备重传 self.udt_send(packet) self.state State.WAIT_ACK_0 if self.current_seq 0 else State.WAIT_ACK_1 return True return False def handle_ack(self, ack_packet): if self.state in [State.WAIT_ACK_0, State.WAIT_ACK_1]: if self.is_corrupt(ack_packet): print([Sender] ACK/NAK损坏等待超时) return if ack_packet[type] NAK: print([Sender] 收到NAK重传分组) self.udt_send(self.saved_packet) else: print([Sender] 收到ACK准备发送下一分组) self.current_seq 1 - self.current_seq # 切换序号 self.state State.WAIT_CALL_0 if self.current_seq 0 else State.WAIT_CALL_1接收方差错检测逻辑class RDTReceiver2(RDTReceiver1): def rdt_rcv(self, packet): if self.is_corrupt(packet): print([Receiver] 检测到分组损坏发送NAK) self.udt_send({type: NAK}) return False data self.extract(packet) self.deliver_data(data) self.udt_send({type: ACK}) return True def is_corrupt(self, packet): # 简化的校验和模拟 return random.random() 0.3 # 30%概率模拟比特差错协议特性对比表特性rdt1.0rdt2.0差错检测❌✅重传机制❌✅确认机制❌✅ (ACK/NAK)状态复杂度低中信道要求完全可靠可能出错4. rdt2.1解决ACK/NAK损坏问题rdt2.0存在致命缺陷如果ACK/NAK本身损坏发送方无法区分新旧分组。rdt2.1通过引入序列号解决这个问题。发送方关键修改class RDTSender21(RDTSender2): def handle_ack(self, ack_packet): if self.is_corrupt(ack_packet): print([Sender] ACK损坏重传当前分组) self.udt_send(self.saved_packet) return if ack_packet[seq] self.current_seq: print(f[Sender] 收到正确ACK{self.current_seq}切换状态) self.current_seq 1 - self.current_seq self.state State.WAIT_CALL_0 if self.current_seq 0 else State.WAIT_CALL_1接收方序列号处理class RDTReceiver21(RDTReceiver2): def __init__(self): super().__init__() self.expected_seq 0 def rdt_rcv(self, packet): if self.is_corrupt(packet): print([Receiver] 分组损坏丢弃并期待重传) return False if packet[seq] ! self.expected_seq: print(f[Receiver] 收到冗余分组{packet[seq]}期待{self.expected_seq}) # 发送上次的ACK self.udt_send({type: ACK, seq: 1 - self.expected_seq}) return False data self.extract(packet) self.deliver_data(data) self.expected_seq 1 - self.expected_seq self.udt_send({type: ACK, seq: self.expected_seq}) return True典型交互场景模拟发送方发送seq0分组接收方正确接收回复ACK0ACK0在传输中损坏发送方超时重传seq0分组接收方识别冗余分组再次发送ACK0发送方收到ACK0转为发送seq1分组5. rdt3.0处理丢包问题的终极方案rdt2.1仍然无法处理分组完全丢失的情况。rdt3.0引入定时器机制成为真正的可靠传输协议。定时器实现要点class RDTSender3(RDTSender21): def __init__(self): super().__init__() self.timer None self.timeout 3.0 # 3秒超时 def start_timer(self): self.timer time.time() def check_timeout(self): if self.timer and time.time() - self.timer self.timeout: print([Sender] 超时重传分组) self.udt_send(self.saved_packet) self.start_timer() return True return False def rdt_send(self, data): if super().rdt_send(data): self.start_timer() return True return False def handle_ack(self, ack_packet): if super().handle_ack(ack_packet): self.timer None # 停止定时器接收方增强class RDTReceiver3(RDTReceiver21): def __init__(self): super().__init__() self.last_ack None def rdt_rcv(self, packet): if self.is_corrupt(packet): return False if packet[seq] ! self.expected_seq: # 立即重发上次的ACK if self.last_ack: self.udt_send(self.last_ack) return False data self.extract(packet) self.deliver_data(data) self.expected_seq 1 - self.expected_seq ack {type: ACK, seq: self.expected_seq} self.last_ack ack self.udt_send(ack) return True丢包场景测试代码# 模拟丢包信道 class LossyChannel: def deliver(self, packet): if random.random() 0.2: # 20%丢包率 print([Channel] 分组丢失) return # 正常传递 receiver.rdt_rcv(packet) if data in packet else sender.handle_ack(packet) # 测试用例 channel LossyChannel() sender RDTSender3() receiver RDTReceiver3() # 发送方持续发送数据 for i in range(5): while not sender.rdt_send(fData{i}): sender.check_timeout() time.sleep(0.5) time.sleep(1)6. 可视化与交互设计为了让学习体验更直观我们使用matplotlib创建协议状态可视化界面import matplotlib.pyplot as plt from matplotlib.animation import FuncAnimation class RDTVisualizer: def __init__(self, sender, receiver): self.fig, (self.ax1, self.ax2) plt.subplots(2, 1) self.sender sender self.receiver receiver def update(self, frame): self.ax1.clear() self.ax2.clear() # 绘制发送方状态 self.ax1.set_title(f发送方状态: {self.sender.state.name}) self.ax1.text(0.5, 0.5, f当前序号: {self.sender.current_seq}, hacenter, vacenter) # 绘制接收方状态 self.ax2.set_title(f接收方状态: 期待序号{self.receiver.expected_seq}) anim FuncAnimation(plt.gcf(), RDTVisualizer(sender, receiver).update, interval1000) plt.show()交互控制台功能手动触发比特差错调整丢包概率控制传输速度查看状态转换历史记录在实际教学中这种可视化模拟器能显著提升学生对以下概念的理解有限状态机的实际应用序列号在可靠传输中的关键作用定时器如何解决丢包问题停等协议的效率瓶颈通过这个项目你不仅理解了RDT协议的设计精髓还掌握了如何将网络协议理论转化为可执行的代码模型。这种技能对于深入理解TCP等实际协议的工作机制至关重要。