:标题: SR Sender实验说明
:作者:
- yangfan
- zhengbw
:时间: 2023年8月6日
==============
SR Sender Lab
==============
Overview
========
选择性重传(Selective Repeat)是自动重复请求(ARQ)的一部分。使用选择性重复,发送方发送由窗口大小指定的帧数,甚至不需要像Go-Back-N ARQ中那样等待接收方的单个ACK。接收端可以选择性地拒绝单个帧,该帧可以单独重传;这与其他形式的ARQ形成了鲜明的对比,后者必须从那个点再次发送每一帧。在选择性重传协议中,接收端接收乱序帧并缓冲它们,发送方分别重新传输已经超时的帧。
在这个实验中,你的任务是实现一个搭建在OpenNetLab上的使用SR协议的发送端。
Getting Started
---------------
1. :download:`下载实验资源 <./resources/sr.zip>` ,解压后进入sr文件夹,其中包含基础的实验代码模板。实验代码包含如下文件:
- :file:`main.py` :本地调试运行文件;
- :file:`receiver.py` :接收方文件,无需修改;
- :file:`sender.py` :发送方文件, `TODO` 部分待编写。
- :file:`testcases.json` :本地评测配置文件。
- :file:`tester` :本地评测运行文件,使用说明见相关文档。
2. 阅读实验任务,完成代码模板中 `TODO` 部分的代码片段。
3. 进行本地测试,完成本地测试后将代码提交到OpenNetLab在线平台进行远程评测。
Tasks
-----
在这个实验中,你需要实现sender.py中的send_available方法以及put方法的设计,并且遵循SR协议:
- 在send_available方法中需要满足以下几点:
- 当收到接收方的确认后,判断该确认是否合法。如果不合法的话,什么也不做;如果合法的话,将对应缓冲区中的帧标记为被确认,如果被确认的帧位于滑动窗口头部,移动滑动窗口直到头部的帧未被确认,并且发送接下来可以发送的帧。
- 每发送一个帧时,保存该帧在缓冲区中。
- 每个缓冲区内的帧对应一个定时器,当定时器超时的时候,重新发送对应的帧。
- put方法表示接收来自receiver数据,由相应的Wire实例调用,用于接收来自receiver的确认数据包。
该实验 `TODO` 部分的伪代码如下:
.. code-block:: text
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中一些属性和方法的解释:
.. py:attribute:: self.seqno_range
:noindex:
序号空间大小。请注意序号空间的序号是从0开始的;
.. py:attribute:: self.window_size
:noindex:
滑动窗口大小;
.. py:attribute:: self.timers
:noindex:
发送方的定时器;
.. py:attribute:: self.env
:noindex:
程序运行的环境;
.. py:attribute:: self.debug
:noindex:
控制运行过程中日志信息输出,可以设置为True以方便调试;
.. py:attribute:: self.proc
:noindex:
发送方的进程;
.. py:function:: new_packet(self, seqno, data) -> Packet
:noindex:
将需要传输的信息内容封装为一个数据包;
@参数: seqno - 数据包的序列号
@参数: data - 数据包所携带的数据内容
@返回类型: 已封装好的一个数据包实例
.. py:function:: timeout_callback(self, packet)
:noindex:
超时处理的回调函数,当sr sender中的超时器超时会自动调用该函数,该函数发送指定的数据包;
@参数: packet - 需要发送的一个数据包实例
.. py:function:: send_packet(self, packet)
:noindex:
发送数据包packet到receiver;
@参数: packet - 需要发送的一个数据包实例
.. py:function:: run(self, env)
:noindex:
在给定的环境中运行发送端;
@参数: env - 程序的运行环境;
.. py:function:: put(self, packet)
:noindex:
处理确认数据包并且发送余下的数据;
@参数: packet - sender接受到的来自receiver的确认数据包
.. py:function:: dprint(self, msg)
:noindex:
打印运行日志信息。
@参数: msg - 需要打印的信息
------------
Testing
=======
1. 进行本地测试
在本机运行 *main.py* 程序。 *main.py* 程序会使用本地的一个测试用例对SR发送端的正确性进行评测并输出运行日志。
.. code-block:: shell
python3 main.py
.. note::
`main.py` 首先实例化类 `Environment` ,创建一个基于事件的网络模拟执行环境。然后 `main.py` 在模拟环境中实例化 GBNsender、GBNreceiver、Wire 类,创建由 `sender` , `receiver` , `wire1` , `wire2` 构成的网络回路进行数据包传输,`Wire` 类主要目的是实现 `sender` 与 `receiver` 之间不可靠的数据传输(模拟数据包的发送时延、丢失和乱序的情况),流程主要分为四步:
1. `sender` 通过 `wire1` 实现数据包的发送
2. `receiver` 通过 `wire1` 中的方法,获取 `sender` 发送的数据包
3. `receiver` 通过 `wire2` 实现数据包的发送
4. `sender` 通过 `wire2` 中的方法,获取 `receiver` 发送的确认数据包
.. figure:: ./images/main.png
:name: gbn_main_process
:align: center
:width: 600px
:alt: image cannot be loaded
main.py 模拟流程
完成程序基本功能的调试后,可以运行可执行文件 `tester` 进行多个测试用例评测,更详细的使用说明见 `相关文档 <./tester.html>`_
2. `提交代码进行远程评测 `_