CS144 Lab2

2026-01-21

具体实现细节请参考 我的实现

Lab2 Start

这个实验要求实现一个TCPReceiver类

这个类是基于前两个实验,所以要熟悉前两个实验完成的接口

越靠后的实验,越是在封装上进行编程,如果忘记了,记得回去看接口

从这个实验开始,我们就真正设计到tcp协议中的内容,包括但不限于标志位,重发等机制

以下是各种标志位的意义

SYN (Synchronize) - 同步序列号

用于建立连接 ACK (Acknowledgment) - 确认标志 用于确认收到数据 RST (Reset) - 重置标志 重置连接

在一个tcp连接中可以同时有多个标志位,上述只是大致阐述,但在实现中仍旧有很多值的注意的细节

(预告:在Lab3中你将要同时处理各种标志位带来的情况)

TCPReceiver

接收函数

void TCPReceiver::receive( TCPSenderMessage message );

这个函数功能很清晰明了,提供一个TCPSenderMessage,我们需要进行解析,并且推送到*流重组器接口

那么思路也是十分简单,但是要注意处理结构体TCPSenderMessage中的标志位

但是接收信息还需要记录isn,和维护状态

  std::optional<Wrap32> isn_ {}; // 记录初始序列号
  bool synced_ {};               // 是否收到sycn

需要在私有成员中添加这两个成员变量

程序的思路是这样的:

收到SYN的数据包后,就设置isn(起始seqno)

(在这个过程中SYN和FIN包都可以携带payload)

随后根据isn计算abs_seqno,计算first_index -> 流重组器接口需要

最后写入流重组器

void TCPReceiver::receive( TCPSenderMessage message )
{
  // 处理重连标志
  if ( message.RST ) {
    reassembler_.reader().set_error();
  }
  // 处理SYN标志
  if ( message.SYN ) {
    isn_ = message.seqno;
    synced_ = true;
  }
  if ( !synced_ )
    return;

  uint64_t checkpoint = reassembler_.writer().bytes_pushed();
  uint64_t abs_seqno = message.seqno.unwrap( isn_.value(), checkpoint );

  // SYN占一个序号
  // 这里如果有SYN建立连接的信号,就让SYN(first_index)占第一个(索引为0)的位置
  uint64_t first_index = ( message.SYN ) ? 0 : abs_seqno - 1;
  reassembler_.insert( first_index, std::move( message.payload ), message.FIN );
}

需要结合理解的就是checkpoint和abs_seqno的计算,结合前面Lab1的笔记理解它的封装和设计思路

可以参考这个博客,讲述很清晰

send()函数