CS144-2021|Lab4 个人实验记录

953 阅读4分钟

lab4

参考:CS144计算机网络 Lab4 | Kiprey's Blog

个人实验留档:cs144-2021

Overview

image.png

这个实验要做的就是将前面实现的几个模块组合起来,最终实现TCPConnection。

但是,在实际实现时,由于这个实验将tcp拆成了sender和receiver这两个模块,而且对于其中的状态转换不是十分清晰,所以实现起来的难度还是比较大的。

Lab 4: The TCP connection

接收到数据段时

  • 如果接收到的数据段的头部设置了rst报文,则可以将输入输出字节流设置为错误状态,关闭tcp连接(unclean close)
  • 否则,正常接收数据段。将数据段传输给TCPReceiver。
  • 如果数据段设置了ACK标志,则需要将当前的ackno以及windiwsize发送给对方
  • 如果接收到的数据段包含有效 seqno,则 TCPConnection 必须至少返回一个 TCP 包作为回复,以告知远程终端 此时的 ackno 和 window size
  • 例外:keep-alives如果接收到包含无效seqno的数据段,可能是对方在确认当前连接是否还有效,则需要发送一个数据段以回应。

参考:TCP KeepAlive机制理解与实践小结 - huey_x - 博客园 (cnblogs.com) TCP KeepAlive探测报文是一种没有任何数据,同时ACK标志被置上的报文,报文中的序列号为上次发生数据交互时TCP报文序列号减1。比如上次本端和对端数据交互的最后时刻,对端回应给本端的ACK报文序列号为 N(即下次本端向对端发送数据,序列号应该为N),则本端向对端发送的保活探测报文序列号应该为 N-1。

if (_receiver.ackno().has_value() && seg.length_in_sequence_space() == 0 && seg.header().seqno == _receiver.ackno().value() - 1) {
  _sender.send_empty_segment();
}

发送数据段时

  • 当 TCPSender 将一个 TCPSegment 数据包添加到待发送队列中时,TCPConnection 需要从中取出并将其发送
  • 从 TCPReciver中获取ackno和windowsize,填充到数据段头部并发出
  • tcp建立连接时的状态转换:

image.png

When time passes

操作系统会调用将要实现的tick函数,以告知时间的流逝。TCPConnection需要:

  • 调用TCPSender的tick函数

  • 如果连续重传次数超过一定上限时,则发送一个带有RST标记的数据段

  • 在适当的情况下关闭tcp连接(clean close) 这里的”适当情况“是指在TCP4次挥手中,客户端主动发出FIN报文时,在第三次挥手时,客户端接收到服务器发动过来的FIN报文,此时,客户端会给服务端发送一个ACK报文并进入TIME-WAIT状态,再经过2MSL的时间,客户端就会静默关闭连接。

    TCP连接的TIME-WAIT状态是为了确保所有的报文都被对方接收。在TCP四次挥手的最后一个阶段,即最后一个ACK报文被发送之后,客户端进入TIME-WAIT状态,等待两倍的最大段生命周期(MSL)后才真正关闭连接。这是为了确保对方接收到了ACK报文,防止对方没有接收到ACK报文导致对方重传FIN报文。此外,TIME-WAIT状态还可以防止由于网络中的延迟而导致的旧的报文段重现,从而使连接恢复到CLOSED状态。

    具体可以看下面的图:

image.png

  • 发送rst报文关闭连接

在 TCP 连接中,通常情况下发送 RST 报文是因为发现了异常。以下是一些可能会发出 RST 报文的情况:

  • 接收到了无效的 TCP 段
  • 当前连接已经被重置
  • 当前连接已经被关闭
  • 当前连接尝试连接的 IP 地址和端口号不正确

具体实现

tcp_connection.hh

tcp_connection.cc

测试

一开始在一个ubuntu22.04的虚拟机上测试,有一些测试总是过不了,后来想有可能是环境问题,换了一个18.04版本的重新配环境就好了。

image.png

image.png

benchmark的结果一般,跟网上的实现差距还是挺大的,有时间再优化了。。

image.png

总结

tcpconnection实现起来还是比较吃力的,需要好好把握tcp连接的状态转换。