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包的接口,取走就是已发送。ExpectNoSegment调maybe_send。期望无消息,如果发了消息,报错。ExpectSeqno调send_empty_message。返回空的TCPSenderMessage,只填seqno。
用于检测seqno是否正确。ExpectSeqnosInFlight用sequence_numbers_in_flight检查发出且未ack的字节数。
push时一旦从Reader中取出数据就要计数。跟踪ack
接收方只有收到了连续的数据才会ack。可能存在连发几个ack,比如[1 5 12],但是sender收到的顺序为[5 12 1]。
这样没问题,因为一旦ack就意味着之前的数据都已经成功收到。
只需维护一个数,看到更大的ack直接更新就行,老的直接抛弃。这里的1直接抛弃。
如果收到的ack大于目前已发送的,为非法,抛弃。
ack底层应该维护安全的64位数据?
ack可能处于数据包的中段,这种情况可以不处理,只处理ack覆盖一个完整包的情况。AckReceived调receive收数据。完了默认会push一下。
每次收到数据时要更新window_size,后续的发送总长度不能超出。直到再次更新。
如果接收端返回window_size为0,要强行使window为1,发送一个数据以便能收到新的window_size。否则可能永远卡住。
window_size为0情况下rto不要加倍。Tick调tick更新时钟。
每次更新时钟时检查超时重发流程。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。