当前位置: 首页 > news >正文

2025 cs144 Lab Checkpoint 2 小白超详细版

文章目录

  • 1 环形索引的实现
    • 1.1 wrap类
      • wrap
      • unwrap
  • 2 实现tcp_receiver
    • 2.1 tcp_receiver的功能
    • 2.2 传输的报文格式
      • TCPSenderMessage
      • TCPReceiverMessage
    • 2.3 如何实现函数
      • receive()
      • send()

1 环形索引的实现

范围是0~2^32-1
需要有SYN(逻辑开头)、FIN(逻辑结尾)

#pragma once#include <cstdint>/** The Wrap32 type represents a 32-bit unsigned integer that:*    - starts at an arbitrary "zero point" (initial value), and*    - wraps back to zero when it reaches 2^32 - 1.*/class Wrap32
{
public:explicit Wrap32( uint32_t raw_value ) : raw_value_( raw_value ) {}/* Construct a Wrap32 given an absolute sequence number n and the zero point. */static Wrap32 wrap( uint64_t n, Wrap32 zero_point );/** The unwrap method returns an absolute sequence number that wraps to this Wrap32, given the zero point* and a "checkpoint": another absolute sequence number near the desired answer.** There are many possible absolute sequence numbers that all wrap to the same Wrap32.* The unwrap method should return the one that is closest to the checkpoint.*/uint64_t unwrap( Wrap32 zero_point, uint64_t checkpoint ) const;Wrap32 operator+( uint32_t n ) const { return Wrap32 { raw_value_ + n }; }bool operator==( const Wrap32& other ) const { return raw_value_ == other.raw_value_; }protected:uint32_t raw_value_ {};
};

1.1 wrap类

表示一个32位无符号整数
需要实现wrap函数、unwrap函数

wrap

  • 静态方法
  • 将一个 64 位的绝对序列号 n 包装成一个 Wrap32 对象,以zero_point 作为起始点
static Wrap32 wrap( uint64_t n, Wrap32 zero_point );

unwrap

uint64_t unwrap( Wrap32 zero_point, uint64_t checkpoint ) const;

功能:该方法用于将当前的 Wrap32 对象解包成一个 64 位的绝对序列号。由于一个 Wrap32 对象可能对应多个 64 位的绝对序列号,因此需要一个 checkpoint 作为参考,返回最接近 checkpoint 的绝对序列号。

2 实现tcp_receiver

2.1 tcp_receiver的功能

在这里插入图片描述receive方法用于接收消息,设置初始序列号并将数据推送至 Reassembler;
send方法用于生成并发送包含确认号和窗口大小的消息,整体预计约 15 行代码

2.2 传输的报文格式

TCPSenderMessage

struct TCPSenderMessage
{Wrap32 seqno { 0 };bool SYN {};std::string payload {};bool FIN {};bool RST {};// How many sequence numbers does this segment use?size_t sequence_length() const { return SYN + payload.size() + FIN; }
};
  • seqno:序列的编号,就是索引的编号,
  • SYN: 字节流的开始
  • payload :传输的字符串
  • FIN:字节流的结束
  • RST: 是否reset
  • sequence_length:总共有多少个seq

TCPReceiverMessage

struct TCPReceiverMessage
{std::optional<Wrap32> ackno {};uint16_t window_size {};bool RST {};
};
  • ackno: 接收器需要的下一个seq编号
  • window_size: 窗口大小,seq的大小限制?
  • RST: reset

2.3 如何实现函数

照例,我们先来看头文件里函数的声明

  void receive( TCPSenderMessage message );TCPReceiverMessage send() const;

receive()

照例,我们先来看头文件里函数的声明

  void receive( TCPSenderMessage message );

receive是服务器端的接收,负责接收发送端传来的消息,再把消息传给重组器(insert)
以终为始,先看一下如果要往reassembler里插入消息的话需要哪些参数,就根据需求来从函数的参数里提取出来即可

void Reassembler::insert( uint64_t first_index, string data, bool is_last_substring )

data、is_last_substring可以直接提取,first_index是绝对索引,需要传来的Wrap格式的索引转换一下
因此就有了:

void TCPReceiver::receive( TCPSenderMessage message )
{//reset为啥要set_error?//const_cast: 去除对象的常量性,也就是说把const writer&转变为writer&if(message.RST == true){const_cast<Writer&>(reassembler_.writer()).set_error();}uint64_t stream_index;if(message.SYN){is_syn = true;_isn = message.seqno;stream_index = 0;}else{//checkpoint(参考点的设置):reassembler_.writer().bytes_pushed()表示当前写入输出流的字数//                       新接收到的序列号通常会接近这个位置 stream_index = message.seqno.unwrap(message.seqno, reassembler_.writer().bytes_pushed());}reassembler_.insert(stream_index, message.payload, message.FIN);
}

send()

照例,我们先来看头文件里函数的声明

  TCPReceiverMessage send() const;

主要任务就是返回一组【ackno(相对)、window_size、rst_flag】,重点就是如何计算相对索引(确认号)
在这里插入图片描述
确认号表示接收方 期望接收的下一个字节的 32 位相对序列号,计算步骤如下:
获取已接收并写入字节流的总字节数(bytes_pushed)。
处理 SYN 和 FIN 标志占用的序列号(各占一个字节)。
将绝对序列号转换为相对序列号(基于初始序列号 ISN)。

窗口大小表示 接收方当前还能接收的字节数,即 字节流缓冲区的剩余容量,在代码中,对应 ByteStream 的 available_capacity() 方法,此外,TCP 协议规定窗口大小字段为 16 位无符号整数(范围:0 ~ 65535),因此必须确保计算结果不超过 UINT16_MAX(65535),故

uint16_t window_size = static_cast<uint16_t>(min(reassembler_.writer().available_capacity(), static_cast<uint64_t>(UINT16_MAX))
);

因此,函数代码如下

TCPReceiverMessage TCPReceiver::send() const
{bool rst_flag = reassembler_.writer().has_error();//处理确认号(希望接受的字节的绝对序列号),流关闭的话需要加上FINuint64_t abs_ackno = reassembler_.writer().bytes_pushed() + 1;if(reassembler_.writer().is_closed()){abs_ackno += 1;}Wrap32 ackno = _isn + abs_ackno;// 计算窗口大小uint16_t window_size = static_cast<uint16_t>(min(reassembler_.writer().available_capacity(), static_cast<uint64_t>(UINT16_MAX)));if (!is_syn) {return {.ackno = std::optional<Wrap32>{},.window_size = window_size,.RST = rst_flag};}return {.ackno = ackno,.window_size = window_size,.RST = rst_flag};
}

相关文章:

  • python 安装win32com.client库
  • ReportLab 导出 PDF(文档创建)
  • vue里provide作用:将一组全局方法注入到 Vue 应用的所有子组件中
  • 【正点原子STM32MP257连载】第四章 ATK-DLMP257B功能测试——USB测试 #USB HOST #USB 鼠标
  • 京东硬核挑战潜规则,外卖算法要变天?
  • 阶段性使用总结-通义灵码
  • 协程从原理到最新的c++协程特性
  • 从服务器多线程批量下载文件到本地
  • 4.14【Q】pc homework3
  • 有序二叉树各种操作实现(数据结构C语言多文件编写)
  • 基础知识:Dify 错误排查
  • 基础学习(4): Batch Norm / Layer Norm / Instance Norm / Group Norm
  • ReactNative中处理安全区域问题
  • 深入解析 OrdinalEncoder 与 OneHotEncoder:核心区别与实战应用
  • Linux——信号量
  • linux 内核 ida机制分析
  • 【SpringMVC】深入解析自定义拦截器、注册配置拦截器、拦截路径方法及常见拦截路径、排除拦截路径、拦截器的执行流程
  • 视觉SLAM和激光SLAM建图输出的文件类型
  • 域控制器升级的先决条件验证失败,证书服务器已安装
  • 基于大模型的反流食管炎手术全流程风险预测与治疗方案研究报告
  • 南部战区回应菲护卫艇非法侵入中国黄岩岛领海:依法警告驱离
  • 重点并不在于设计更聪明的机器,而在于开发宇宙技术的多样性
  • 南华期货递表港交所,冲刺第二家“A+H”股上市期货公司
  • 航行警告!南海部分水域进行军事训练,禁止驶入
  • 恒安集团创始人许连捷逝世:白手起家缔造百亿纸品巨头,个人曾捐赠超10亿
  • 鲁比奥在法国只字不提关税,美国威胁下欧盟勉力维持统一战线