cs144 LAB1 基于滑动窗口的碎片字节流重组器

news2024/11/17 15:58:47

一.StreamReassembler.capacity 的意义

StreamReassembler._capacity 的含义:

capacity

  • ByteStream 的空间上限是 capacity
  • StreamReassembler 用于暂存未重组字符串片段的缓冲区空间 StreamReassembler.buffer 上限也是 capacity
  • 蓝色部分代表了已经被上层应用读取的已重组数据
  • 绿色部分代表了 ByteStream 中已经重组并写入但还未被读取的字节流所占据的空间大小
  • 红色部分代表了 StreamReassembler 中已经缓存但未经重组的若干字符串片段所占据的空间大小
  • 同时绿色和红色两部分加起来的空间总占用大小不会超过 capacity(事实上会一直小于它)

从代码层面来看:

  • first unread 的索引等于 ByteStream 的 bytes_read() 函数的返回值(我们一般不关注这个值)
  • first unassembled 的索引等于 ByteStream 的 bytes_write() 函数的返回值(起始就是下一个期望的字节在流中的序号)
  • first unacceptable 的索引等于 ByteStream 的 bytes_read() 加上 capacity 的和(已超过 ByteStream 的 buffer 限制)
  • first unread 和 first unacceptable 这两个边界是动态变化的,每次重组结束都需要更新。

最后,有个很重要点,ByteStream 和 StreamReassembler 的总容量有固定的限制,多余的数据需要丢弃(此需要对端重传数据,这就引出了重传等知识点)

二.滑动窗口碎片重组算法 

        每次收到的data数据由于网络传输不可靠的原因会产生乱序,重叠。需要对每次收到的碎片序列进行重组。可以定义装配器的窗口大小为capacity,范围为[_first_unassembled,_first_unassembled + _capacity]。超出此范围的字节将被丢弃(实验要求,之后会引出重传)。窗口会随着第一个期望的字节序号进行移动即_first_unassembled。每次计算缓冲区第一个期望字节序号,并保障每个字节碎片都在窗口范围内,这需要对碎片进行裁剪,裁剪过后的碎片可以直接加入缓存区。

        可分为下面几个步骤完成:

1.计算重组器窗口起始位置,结束位置。

2.判断碎片是否合法,不合法则直接丢弃。

3.裁剪碎片,使其满足缓冲区要求。

4.碎片加入缓存区。

5.缓存区写入流。(如果缓冲区头部有元素的话)

6.判断EOF。

        需要注意EOF这里有几个大坑,首先是EOF可能会提早到来,这时不能直接结束流写入需要进行判断。第二是EOF可能与其他流重叠,故而可以记录EOF的合法结束字节位置来判断是否真正需要停止流写入。

#ifndef SPONGE_LIBSPONGE_STREAM_REASSEMBLER_HH
#define SPONGE_LIBSPONGE_STREAM_REASSEMBLER_HH

#include "byte_stream.hh"

#include <cstdint>
#include <string>
#include <deque>

//! \brief A class that assembles a series of excerpts from a byte stream (possibly out of order,
//! possibly overlapping) into an in-order byte stream.
class StreamReassembler {
  private:
    // Your code here -- add private members as necessary.
    std::deque<std::string::value_type> _reassembler_buffer;  //重组器缓冲区
    std::deque<bool> _bytes_flag; //重组器字节标志位

    std::size_t _unassembaled_bytes = 0;  //未被装配的字节
    bool _is_eof = false; //判断子序列是否含有EOF
    std::size_t _eof_index = 0; //记录EOF段最后一个字节的位置

    ByteStream _output;  //!< The reassembled in-order byte stream
    size_t _capacity;    //!< The maximum number of bytes

  public:
    //! \brief Construct a `StreamReassembler` that will store up to `capacity` bytes.
    //! \note This capacity limits both the bytes that have been reassembled,
    //! and those that have not yet been reassembled.
    StreamReassembler(const size_t capacity);

    //! \brief Receive a substring and write any newly contiguous bytes into the stream.
    //!
    //! The StreamReassembler will stay within the memory limits of the `capacity`.
    //! Bytes that would exceed the capacity are silently discarded.
    //!
    //! \param data the substring
    //! \param index indicates the index (place in sequence) of the first byte in `data`
    //! \param eof the last byte of `data` will be the last byte in the entire stream
    void push_substring(const std::string &data, const uint64_t index, const bool eof);

    //! \name Access the reassembled byte stream
    //!@{
    const ByteStream &stream_out() const { return _output; }
    ByteStream &stream_out() { return _output; }
    //!@}

    //! The number of bytes in the substrings stored but not yet reassembled
    //!
    //! \note If the byte at a particular index has been pushed more than once, it
    //! should only be counted once for the purpose of this function.
    size_t unassembled_bytes() const;

    //! \brief Is the internal state empty (other than the output stream)?
    //! \returns `true` if no substrings are waiting to be assembled
    bool empty() const;
};

#endif  // SPONGE_LIBSPONGE_STREAM_REASSEMBLER_HH
#include "stream_reassembler.hh"

// Dummy implementation of a stream reassembler.

// For Lab 1, please replace with a real implementation that passes the
// automated checks run by `make check_lab1`.

// You will need to add private members to the class declaration in `stream_reassembler.hh`

template <typename... Targs>
void DUMMY_CODE(Targs &&... /* unused */) {}

using namespace std;

StreamReassembler::StreamReassembler(const size_t capacity) : 
_reassembler_buffer(capacity, '\0'),
_bytes_flag(capacity, false),
_output(capacity),
_capacity(capacity) {}

//! \details This function accepts a substring (aka a segment) of bytes,
//! possibly out-of-order, from the logical stream, and assembles any newly
//! contiguous substrings and writes them into the output stream in order.
void StreamReassembler::push_substring(const string &data, const size_t index, const bool eof) {
    //判断index是否合法
    std::size_t _first_unassembled = _output.bytes_written();   //每次计算期望的字节序号
    std::size_t _first_unacceptable = _first_unassembled + _capacity;   //第一个不允许装配的字节序号
    if(index >= _first_unacceptable || index + data.length() < _first_unassembled)
        return;
    
    //滑动窗口位于[_first_unassembled,_first_unassembled + _capacity]之间只有其中元素可以入队,对data进行裁剪
    std::size_t new_index = index;
    std::size_t new_end = index + data.length();
    if(new_index < _first_unassembled)
        new_index = _first_unassembled;
    if(new_end >= _first_unacceptable)
        new_end = _first_unacceptable;

    //裁剪完成后data的起始位置符合滑动窗口要求,入队
    for(std::size_t i = new_index; i < new_end; ++i){
        if(!_bytes_flag[i - _first_unassembled]){
            _reassembler_buffer[i - _first_unassembled] = data[i - index];   //入队
            _bytes_flag[i - _first_unassembled] = true;  //相应标志位置位
            ++_unassembaled_bytes;  //缓冲区计数增加
        }
    }

    //写入流操作(当装配缓冲区头部有元素那么一定是顺序的直接写入流)
    string wait_to_write{};
    while(_bytes_flag.front()){
        wait_to_write += _reassembler_buffer.front();
        _bytes_flag.pop_front();
        _reassembler_buffer.pop_front();
        _bytes_flag.emplace_back(false);        //维护缓冲区大小
        _reassembler_buffer.emplace_back('\0'); //维护缓冲区大小
    }
    if(wait_to_write.size() > 0){
        int out_bytes = _output.write(std::move(wait_to_write));
        _unassembaled_bytes -= out_bytes;
    }
    
    //检查eof
    if(eof){
        _is_eof = true;
        _eof_index = new_end;
    }
    if(_is_eof && _eof_index == _output.bytes_written())
        _output.end_input();
}

size_t StreamReassembler::unassembled_bytes() const { return _unassembaled_bytes; }

bool StreamReassembler::empty() const { return _unassembaled_bytes == 0; }

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1839160.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

计算机专业毕设-springboot论坛系统

1 项目介绍 基于SSM的论坛网站&#xff1a;后端 SpringBoot、Mybatis&#xff0c;前端thymeleaf&#xff0c;具体功能如下&#xff1a; 基本功能&#xff1a;登录注册、修改个人信息、修改密码、修改头像查看帖子列表&#xff1a;按热度排序、按更新时间排序、查看周榜月榜查…

棱镜七彩荣获CNNVD两项大奖,专业能力与贡献再获认可!

6月18日&#xff0c;国家信息安全漏洞库&#xff08;CNNVD&#xff09;2023年度工作总结暨优秀表彰大会在中国信息安全测评中心成功举办。棱镜七彩凭借在漏洞方面的突出贡献和出色表现&#xff0c;被授予“2023年度优秀技术支撑单位”与“2023年度最佳新秀奖”。 优秀技术支撑单…

Gobject tutorial 七

The GObject base class GObject是一个fundamental classed instantiatable type,它的功能如下&#xff1a; 内存管理构建/销毁实例set/get属性方法信号 /*** GObjectClass:* g_type_class: the parent class* constructor: the constructor function is called by g_object…

最新技术:跨境电商源码,应对多国市场需求,让您轻松开展全球业务!

随着全球化进程的不断推进&#xff0c;跨境电商已成为企业拓展国际市场的重要途径。为了满足不同国家和地区消费者不断增长的需求&#xff0c;跨境电商源码应运而生&#xff0c;为企业提供了便捷高效的全球化业务发展方案。 一、全球化运营的关键 跨境电商源码的核心功能在于…

极具吸引力的小程序 UI 风格

极具吸引力的小程序 UI 风格

小白速成AI大模型就看这份资源包

前言 在数字化浪潮席卷全球的今天&#xff0c;人工智能&#xff08;AI&#xff09;技术已成为推动社会进步的重要引擎。尤其是AI大模型&#xff0c;以其强大的数据处理能力和广泛的应用前景&#xff0c;吸引了无数人的目光。然而&#xff0c;对于初学者“小白”来说&#xff0…

ProtoBuf序列化协议简介

首先&#xff0c;常见的序列化方法主要有以下几种&#xff1a; TLV编码及其变体(tag, length, value)&#xff1a; 比如ProtoBuf。文本流编码&#xff1a;XML/JSON固定结构编码&#xff1a;基本原理是&#xff0c;协议约定了传输字段类型和字段含义&#xff0c;和TLV类似&…

MyBatis框架基础

文章目录 1 MyBatis概述2 MyBatis入门2.1 相关依赖2.2 properties配置文件2.3 预编译SQL 3 基本操作3.1 新增操作3.2 删除操作3.3 更新操作3.4 查询操作 4 动态SQL4.1 XML映射文件4.2 if/set/where标签4.3 foreach标签4.4 sql/include标签 5 参考资料 1 MyBatis概述 MyBatis是…

入侵检测系统(IDS)

入侵检测 入侵检测&#xff08;Intrusion Detection&#xff09;是指发现或确定入侵行为存在或出现的动作&#xff0c;也就是发现、跟踪并记录计算机系统或计算机网络中的非授权行为&#xff0c;或发现并调查系统中可能为视图入侵或病毒感染所带来的异常活动。 入侵检测系统 …

XL5300 dTOF测距模块 加镜头后可达7.6米测距距离 ±4%测距精度

XL5300 直接飞行时间&#xff08;dToF&#xff09;传感器是一个整体方案dTOF 模组&#xff0c;应用设计简单。片内集成了单光子雪崩二极管&#xff08;SPAD&#xff09;接收阵列以及VCSEL激光发射器。利用自主研发的 SPAD 和独特的ToF 采集与处理技术&#xff0c;XL5300模块可实…

NV-Embed论文阅读笔记

这是NVIDIA的一篇论文&#xff0c;LLM通常使用的是GPT的decoder范式作为一个生成模型&#xff0c;文章探讨如何利用这样的decoder生成模型来实现BERT这样的encoder的功能&#xff0c;即提取有效的embedding。现有的方法提取embedding的方式无非是 1 mean pooling&#xff1b; 2…

无线领夹麦克风哪个牌子好用?一文揭秘哪种领夹麦性价比最高!

​无线领夹麦克风&#xff0c;无疑是现代音频技术的杰出代表。它摆脱了传统有线麦克风的束缚&#xff0c;让声音的传播更加自由、灵活。无论是追求极致音质的音乐爱好者&#xff0c;还是需要高效沟通的商务人士&#xff0c;无线领夹麦克风都能满足你的需求&#xff0c;让你的声…

HarmonyOS 角落里的知识 —— 状态管理

一、前言 在探索 HarmonyOS 的过程中&#xff0c;我们发现了许多有趣且实用的功能和特性。有些总是在不经意间或者触类旁通的找到。或者是某些开发痛点。其中&#xff0c;状态管理是ArkUI开发非常核心的一个东西&#xff0c;我们进行了大量的使用和测试遇到了许多奇奇怪怪的问…

AD层次原理图绘制

一、在原理图中添加端口 二、添加层次图 三、更新层次图 四、也可以先画层次图&#xff0c;再绘制原理图&#xff0c;这里就不做演示了

天地图 uniapp使用笔记

官网地址&#xff1a;天地图API 效果&#xff1a; <template><view><!-- 显示地图的DOM节点 --><view id"container" class"content"></view><!-- END --><!-- 数据显示 --><h3>城市名称(IP属地)&#x…

关于归一化能量与归一化功率(连续与离散+1)

前言&#xff1a; ① 周期信号 与 直流信号 都是功率信号 ②一个信号可以既不是能量信号也不是功率信号&#xff0c;但不可能既是能量信号又是功率信号 归一化能量 对于一个连续时间信号 ( x(t) )&#xff0c;归一化能量 ( E ) 的定义为&#xff1a; E lim ⁡ T → ∞ ∫ −…

某宝APP参数通过SDK把APP参数转URL参数链接方法

app里参数无法在电脑端或者在没有XX宝的手机里支付, 所以需要转成H5参数进行代付操作 出某xx宝 支付sdk转h5链接方式算法

苹果不会等到明年才对 Siri 进行改进|TodayAI

据彭博社报道&#xff0c;今年苹果&#xff08;APPLE&#xff09;将推出一个更令人满意的 Siri。 当 iOS 18 今年秋季推出时&#xff0c;Siri 的功能不仅仅是让你的 iPhone 边缘显示彩虹光环。虽然苹果智能功能要到 2025 年才会向非测试版用户推出&#xff0c;但据报道&#x…

工作人员能从轧钢测径仪上获取哪些有效信息?

轧钢测径仪安装在轧钢生产线中&#xff0c;无论是热轧还是冷轧&#xff0c;都不能阻挡测径仪的高速无损高精检测。它采用八轴测量系统&#xff0c;能全方位检测外径尺寸&#xff0c;并且配备了测控软件系统&#xff0c;为工作人员提供更加丰富的产线信息。 普通轧钢测径仪能获…

跨境电商必备?揭秘原生IP的作用

一、什么是原生IP&#xff1f; 原生IP&#xff08;Native IP&#xff09;是指由互联网服务提供商&#xff08;ISP&#xff09;或服务器提供商直接分配给用户的IP地址&#xff0c;这种IP地址直接与用户设备或网络相连&#xff0c;也就是指这个IP的注册地址和服务器机房所在的国…