在实现了接收端的 TCPReceiver 类和发送端的 TCPSender 类后,本节实验实现掌管这两个类,向用户提供一个完整的 TCP 连接抽象的 TCPConnection 类。正如讲义标题所写,完成本节的实验后,我们是真正攀登上了一个高峰(summit),也是完成了本门课程最重要精华的部分。
事前提醒,本节的测试量非常大,其中会用你的 TCP 实现与 Linux 的 TCP 实现进行各种条件的交互,之前的 Sender 和 Receiver 类在实现上如果有潜在问题也都会被暴露出来。所以,如果你在尝试自己实现,请做好耐心 Debug 的准备。虽然直接看其它人的 blog 可能感觉逻辑都很自然,但自己动手是完全不一样的。我当时也花了 2 整天左右才通过了所有测试。

TCP 是全双工通信,即双方可以同时发送/接收信息。如图所示,TCPConnection 类应该是架设在 TCPSender 和 TCPReceiver 之上的。当 Sender 需要发送数据包时,从其发送队列 _segments_out 中取出数据包并实际发送出去;当接收到数据包时,做必要处理后交给 Receiver 处理。另外,之前我们一直没有关注 TCP 包头中很重要的一个标识 RST,这也是 TCPConnection 要负责的,即异常状态的处理。最后,TCPConnection 还应该处理好连接的终止,包括正常终止和异常终止两种情况。以下我们分别来讨论这几个问题以及实现思路。
注:这里发送的实现其实还是将数据包从 Sender 取出转存到 TCPConnection 的一个发送队列中,之后会由更上层的所有者实际负责发送
对应函数:void segment_received(const TCPSegment &seg)。
_shutdown(bool) 函数,参数代表是正常还是异常结束,这里即为异常结束。否则:segment_received。ack_received。_clear_sendbuf),在任何可能使 Sender 发送数据包的语句之后都调用该函数。与 Sender 相同,TCPConnection 也是通过其 tick 函数被调用而被动的感知时间的经过。当 tick 被调用时:
tick。_shutdown(false)。以上已经讨论过连接异常终止的两种情况,即主动检测到重传次数过多或被动收到对方的 RST 包,这里主要讨论的是连接的正常终止。
理论上来说,通过不可信连接通信的双方无法绝对确保达成共识(参考:两军问题),不过 TCP 设计了一种可信度较高的方案。以一方(local 方)的观点来看,至少有四件事成立才能正常终止连接:
除了运行自动化测试外,本节完成后已经可以用两个自己的 TCP 端进行通信,以及用自己的 TCP 代替 Lab0 中的 TCPSocket 与真实的服务器进行通信,还可以测试自己 TCP 实现的性能,操作方法讲义中都有描述。
完整代码链接:
tcp_connection.hh
tcp_connection.cc
通关截图 😎


