SR Sender Lab

Overview

选择性重传(Selective Repeat)是自动重复请求(ARQ)的一部分。使用选择性重复,发送方发送由窗口大小指定的帧数,甚至不需要像Go-Back-N ARQ中那样等待接收方的单个ACK。接收端可以选择性地拒绝单个帧,该帧可以单独重传;这与其他形式的ARQ形成了鲜明的对比,后者必须从那个点再次发送每一帧。在选择性重传协议中,接收端接收乱序帧并缓冲它们,发送方分别重新传输已经超时的帧。

在这个实验中,你的任务是实现一个搭建在OpenNetLab上的使用SR协议的发送端。

Getting Started

  1. 下载实验资源 ,解压后进入sr文件夹,其中包含基础的实验代码模板。实验代码包含如下文件:

    • main.py :本地调试运行文件;

    • receiver.py :接收方文件,无需修改;

    • sender.py :发送方文件, TODO 部分待编写。

    • testcases.json :本地评测配置文件。

    • tester :本地评测运行文件,使用说明见相关文档。

  2. 阅读实验任务,完成代码模板中 TODO 部分的代码片段。

  3. 进行本地测试,完成本地测试后将代码提交到OpenNetLab在线平台进行远程评测。

Tasks

在这个实验中,你需要实现sender.py中的send_available方法以及put方法的设计,并且遵循SR协议:

  • 在send_available方法中需要满足以下几点:

    • 当收到接收方的确认后,判断该确认是否合法。如果不合法的话,什么也不做;如果合法的话,将对应缓冲区中的帧标记为被确认,如果被确认的帧位于滑动窗口头部,移动滑动窗口直到头部的帧未被确认,并且发送接下来可以发送的帧。

    • 每发送一个帧时,保存该帧在缓冲区中。

    • 每个缓冲区内的帧对应一个定时器,当定时器超时的时候,重新发送对应的帧。

  • put方法表示接收来自receiver数据,由相应的Wire实例调用,用于接收来自receiver的确认数据包。

该实验 TODO 部分的伪代码如下:

function send_available(packet) {
    # sender初始化时已定义相应的 buffer 和 times
    create buffer : outbound: Deque[QueueItem] = deque()
    create times  : timers: Deque[Timer] = deque()
    if len(buffer) > 0 and the head of buffer is acked:
        update buffer
        update times

    while (condition) {
        send packets
        add these packets to buffer and times
    }
}

# 实验模板已经给出send_packet方法的具体实现
def send_packet(self, packet: Packet):
        self.dprint(f"send {packet.payload} on seqno {packet.packet_id}")
        assert self.out
        self.out.put(packet)

func put(packet):
    receive Packet from SR receiver as p
    if p['ackno'] is valid ackno {
        mark the corresponding packet in buffer as acked
        send available packet
    }
    if all packets are sent and acked {
        self.finish_channel.put(True)  //finish_channel表示结束条件
    }

Tips

你可以通过 SR交互演示 来帮助自己更好地理解SR的过程。

sender.py和receiver.py中一些属性和方法的解释:

self.seqno_range

序号空间大小。请注意序号空间的序号是从0开始的;

self.window_size

滑动窗口大小;

self.timers

发送方的定时器;

self.env

程序运行的环境;

self.debug

控制运行过程中日志信息输出,可以设置为True以方便调试;

self.proc

发送方的进程;

new_packet(self, seqno, data) Packet

将需要传输的信息内容封装为一个数据包;

@参数: seqno - 数据包的序列号

@参数: data - 数据包所携带的数据内容

@返回类型: 已封装好的一个数据包实例

timeout_callback(self, packet)

超时处理的回调函数,当sr sender中的超时器超时会自动调用该函数,该函数发送指定的数据包;

@参数: packet - 需要发送的一个数据包实例

send_packet(self, packet)

发送数据包packet到receiver;

@参数: packet - 需要发送的一个数据包实例

run(self, env)

在给定的环境中运行发送端;

@参数: env - 程序的运行环境;

put(self, packet)

处理确认数据包并且发送余下的数据;

@参数: packet - sender接受到的来自receiver的确认数据包

dprint(self, msg)

打印运行日志信息。

@参数: msg - 需要打印的信息


Testing

  1. 进行本地测试

在本机运行 main.py 程序。 main.py 程序会使用本地的一个测试用例对SR发送端的正确性进行评测并输出运行日志。

python3 main.py

Note

main.py 首先实例化类 Environment ,创建一个基于事件的网络模拟执行环境。然后 main.py 在模拟环境中实例化 GBNsender、GBNreceiver、Wire 类,创建由 sender , receiver , wire1 , wire2 构成的网络回路进行数据包传输,Wire 类主要目的是实现 senderreceiver 之间不可靠的数据传输(模拟数据包的发送时延、丢失和乱序的情况),流程主要分为四步:

  1. sender 通过 wire1 实现数据包的发送

  2. receiver 通过 wire1 中的方法,获取 sender 发送的数据包

  3. receiver 通过 wire2 实现数据包的发送

  4. sender 通过 wire2 中的方法,获取 receiver 发送的确认数据包

image cannot be loaded

main.py 模拟流程

完成程序基本功能的调试后,可以运行可执行文件 tester 进行多个测试用例评测,更详细的使用说明见 相关文档

  1. 提交代码进行远程评测