Lab 3:the TCP sender
本文记录了 Lab 3:the TCP sender 的实验过程
Lab 3: the TCP sender
实现 TCP 的发送侧,即
TCPSender
。TCPSender
负责
- 根据
TCPReceiver
发回的窗口大小来改变自己的窗口大小- 从
ByteStream
中读取数据,将 stream 变成向外发送的 TCP segment(如果需要的话会在 segment 中带上 SYN/FIN 控制标志)- 跟踪那些已经被发送但是还未被 receiver 确认的 segments,在 Lab 中称这些 segments 为 “outstanding” segments
- 如果一个 segment 在发送后经过一段时间没有被确认,那么重传这个 segment
思路
一开始,看了下实验指导书,发现不是很理解要怎么实现这几个接口,然后对着 test case 来理解这个 lab 要我们怎么实现,例如 send_connect.cc 这个文件
1 | { |
它是测试 SYN 的发送,只发送了一个携带 SYN = true
的 segment,还记得 SYN 占用一个序列号嘛?因此 bytes_in_flight
应该等于 1。接下来是 SYN Ack test:
1 | { |
这个时候需要通过 ack_received
函数处理收到的 ackno
和 winfow_size
。wrong ack test 需要你你在 ack_received
函数中判断收到的 ackno
是否合法。
最后在 SYN acked, data 中,在发送 SYN、确认之后还发送了一个带有数据的 segment,再对它进行确认。
Task #1
首先,我们先不用管 segment 的重传。为了完成必要的功能,我们需要在头文件中添加必要的私有成员变量,例如窗口大小
window_size
、上一个被确认的序列号last_ackno
、已经被发送但还未被确认的个数bytes_in_flight
等等。
1 | //! last ackno |
注意
- TCPSender 通过
fill_window
函数来发送 segment,我们需要处理发送 SYN、数据、FIN segments。能否发送它们需要根据当前窗口的剩余容量 - 发送完一个 segment 记得更新
bytes_in_flight
和_next_seqno
ack_received
函数中需要根据ackno
和winfow_size
更新我们添加的私有成员变量,然后根据ackno
移除那些已经被确认的 “outstanding” segments。使用length_in_sequence_space
函数获得这个 segment 的长度
Task #2
现在我们需要完成计时器部分的代码了,由于一个 segment 在发送之后,会启动一个计时器,当超时后,会重传这个 segment。对于计时器的设计,可以将它设计成一个类。
对于重传计时器的实现需要注意:
- 计时器的 time passing 是通过调用
tick
函数实现的,而不是调用 OS 或者 CPU 的time
或者clock
- retransmission timeout (RTO) 是重新发送一个 outstanding TCP segment 之前等待的毫秒数
- 每当发送一个包含数据的 segment 时,如果计时器还未启动,则启动计时器
- 当所有的 outstanding TCP segment 都被确认时,关闭计时器
- 当计时器超时
- 重传那个最早发送、但却未被确认的 segment
- 如果窗口大小不为 0:(i)增加连续重传的次数。在下个 Lab 中,TCPConnection 会根据这个信息来决定是否终止连接。(ii)将 RTO 的值加倍。
- 当 sender 收到了 receiver 发送的 ackno 时,它会
- 将 RTO 设置回初始值
- 如果 sender 存在 outstanding data,重新启动重传计时器,这样它就会在经过 RTO 后过期
- 重新设置 consecutive retransmissions 为 0
测试
1 | make -j4 |