CS144 Lab Assignments - 手写TCP - LAB3

CS 144: Introduction to Computer Networking, Fall 2020
https://cs144.github.io/

My Repo
https://github.com/wine99/cs144-20fa

思否主页:https://segmentfault.com/u/wine99

总体思路

tick 不需要我们来调用,参数的意义是距离上次 tick 被调用过去的时间,也不需要我们来设定。我们只需要在 tick 中实现,通过参数判断过去了多少时间,需要执行何种操作即可。

注意根据文档,我们要不需要实现选择重传,而是类似回退 N,需要存储已发送并且未被确认的段,进行累计确认,超时时只要重传这些段中最早的那一个即可。

TCPReceiver 调用 unwrap 时的 checkpoint 是上一个接收到的报文段的 absolute_seqno,TCPSender 调用 unwrap 时的 checkpoint 是 _next_seqno

我的实现中计时器开关的处理:

  • 发送新报文段时若计时器未打开,开启
  • ack_received() 中,如果有报文段被正确地确认,重置计时器和 RTO,如果所有报文段均被确认(bytes in flight == 0),关闭计时器
  • tick() 中,若计时器为关闭状态,直接返回,否则累加计时然后处理超时

添加的成员变量

class TCPSender {
   
  private:
    bool _syn_sent = false;
    bool _fin_sent = false;
    uint64_t _bytes_in_flight = 0;
    uint16_t _receiver_window_size = 0;
    uint16_t _receiver_free_space = 0;
    uint16_t _consecutive_retransmissions = 0;
    unsigned int _rto = 0;
    unsigned int _time_elapsed = 0;
    bool _timer_running = false;
    std::queue<TCPSegment> _segments_outstanding{
   };

    bool _ack_valid(uint64_t abs_ackno);
    void _send_segment(TCPSegment &seg);
};
  • send_segment(TCPSegment &seg) 只在 fill_window() 中被调用,重传只需要 _segments_out.push(_segments_outstanding.front())
  • _receiver_window_size 保存收到有效(有效的含义见上面 ack_valid())确认报文段时,报文段携带的接收方窗口大小
  • _receiver_free_space 是在 _receiver_window_size 的基础上,再减去已发送的报文段可能占用的空间(_bytes_in_flight

fill_window() 实现

  • 如果 SYN 未发送,发送然后返回
  • 如果 SYN 未被应答,返回
  • 如果 FIN 已经发送,返回
  • 如果 _stream 暂时没有内容但并没有 EOF,返回
  • 如果 _receiver_window_size 不为 0
    1. receiver_free_space 不为 0,尽可能地填充 payload
    2. 如果 _stream 已经 EOF,且 _receiver_free_space 仍不为 0,填上 FIN(fin 也会占用 _receiver_free_space)
    3. 如果 _receiver_free_space 还不为 0,且 _stream 还有内容,回到步骤 1 继续填充
  • 如果 _receiver_window_size 为 0,则需要发送零窗口探测报文
    • 如果 _receiver_free_space 为 0
      • 如果 _stream 已经 EOF,发送仅携带 FIN 的报文
      • 如果 _stream 还有内容,发送仅携带一位数据的报文
    • 之所以还需要判断 _receiver_free_space 为 0,是因为这些报文段在此处应该只发送一次,后续的重传由 tick() 函数控制,而当发送了零窗口报文段后 _receiver_free_space 的值就会从原来的与 _receiver_window_size 相等的 0 变成 -1
void TCPSender::fill_window() {
   
    if (!_syn_sent) {
   
        _syn_sent = true;
        TCPSegment seg;
        seg.header().syn = true;
        send_segment(seg);
        return;
    }
    if (!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值