cs144网络课程3 TCP sender#

环境#

https://cs144.github.io/assignments/check3.pdf

commit lab2的代码。

merge lab3的代码
git merge origin/check3-startercode

编译/测试
cmake --build build
cmake --build build --target check3

TCPSender#

TCPSender需要干一系列事情

  • 关注TCPReceiver的window。

  • 从本地ByteStream取数据,根据对端的window组成tcp包给对端。

  • 关注发出去的包是否被对端ack。

  • 超时没被ack的包,重发。

可以看看rfc9293中的rto相关内容。

多久算超时?按https://www.ietf.org/rfc/rfc6298.html第5节推荐的算法来。

实现#

  • Push
    byte_stream_helpers.cc中的read()Reader中取数据。
    生成TCPSenderMessage待发送。payload不要大于TCPConfig::MAX PAYLOAD SIZE。可生成多个。

  • ExpectMessage会用maybe_send拿到一个TCPSenderMessage,然后检查它是否符合要求。
    maybe_send就是上层应用来取tcp包的接口,取走就是已发送。

  • ExpectNoSegmentmaybe_send。期望无消息,如果发了消息,报错。

  • ExpectSeqnosend_empty_message。返回空的TCPSenderMessage,只填seqno。
    用于检测seqno是否正确。

  • ExpectSeqnosInFlightsequence_numbers_in_flight检查发出且未ack的字节数。
    push时一旦从Reader中取出数据就要计数。

  • 跟踪ack
    接收方只有收到了连续的数据才会ack。可能存在连发几个ack,比如[1 5 12],但是sender收到的顺序为[5 12 1]。
    这样没问题,因为一旦ack就意味着之前的数据都已经成功收到。
    只需维护一个数,看到更大的ack直接更新就行,老的直接抛弃。这里的1直接抛弃。
    如果收到的ack大于目前已发送的,为非法,抛弃。
    ack底层应该维护安全的64位数据?
    ack可能处于数据包的中段,这种情况可以不处理,只处理ack覆盖一个完整包的情况。

  • AckReceivedreceive收数据。完了默认会push一下。
    每次收到数据时要更新window_size,后续的发送总长度不能超出。直到再次更新。
    如果接收端返回window_size为0,要强行使window为1,发送一个数据以便能收到新的window_size。否则可能永远卡住。
    window_size为0情况下rto不要加倍。

  • Ticktick更新时钟。
    每次更新时钟时检查超时重发流程。initial_RTO_ms为初始超时时间。
    只要存在已发出未ack的数据,就要保证timer开启。
    只有一个timer,并不是每个数据包一个timer。
    重发的永远是未ack数据包中sn最小的那个。
    每超时一次rto加倍。要记录连续重发次数,consecutive_retransmissions中返回给上层。
    一旦出现有效的ack,关timer,rto恢复初始值。如果仍存在其他等待ack的包,timer要打开。

  • Close会先关闭ByteStream再push。
    要在push中读ByteStream之后检查ByteStream是否is_finished()。如果是,带上FIN。