CS144 Lab:Lab1
本文最后更新于 218 天前,内容如有失效请评论区留言。

由于写这个 Lab1 的笔记距离完成 Lab1 实验1 已经过去了很久,所以可能会比较简略

Lab1 介绍

在 Lab1 中,需要实现一个流重组器:将传入的没一份打乱的字节流重新组合形成原来的有序的字节流。即实现 StreamReassembler 类。

为什么要这样做? TCP 对处理乱序和重复包的健壮性来自于它能将字节流的任意摘录拼接回原始流的能力。在离散的可测试模块中实现这一功能将使处理传入段变得更加容易

image-20230728165319736

注意:

  • 每个流碎片由起始位置,长度,字符串内容组成
  • 碎片会重叠,但是不会有冲突
  • 一个字节没有被写入 _output 当且仅当它前面的那个字符没有被写入 _output。换而言之如果一个标号为 index 的字节存在,并且 [0, index - 1] 的字符存在那么它就必须被写入 _output 中。(0 号字符一存在就要被写入 _output 中)
  • 会存在字符串内容为空的带有 EOF 标志的碎片

需要理解关于 StreamReassembler 类的 capacity 的指的是什么,实际上你需要保证 _output 中未被读取的字节数 + 未重组完成的字节数 <= capacity。

image-20230728165420200

具体实现上一些博客是用 std::set 维护,对于相交情况分类讨论。我开始想着反正都带 $\log $ 的,直接用 std::map 暴力模拟即可。

但是这么搞常数比较大,通过 Lab1 的测试时间超过了 1s,7/26 测试点为 0.62s,没有达到最低要求:

image-20230728172242021

后来我发现只需要稍微改变一下就能够把 std::map 换成 std::vector 了,速度顿时提升了不少,还去掉了 $\log $ 。

代码

就只放 std::vector 版本了

声明部分:

//! \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.

    ByteStream _output;  //!< The reassembled in-order byte stream
    size_t _capacity;    //!< The maximum number of bytes
    std::vector<std::pair<char, bool> > _stream; //!< The current part of the reassembled byte stream
    size_t _cur_index;   //!< The index of the first byte of the reassembled byte stream
    size_t _eof_index;         //!< The index of the last byte of the entire stream
    size_t _unassembled_bytes_cnt; //!< The number of bytes that have not yet been reassembled

  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;
};

成员函数实现部分:

StreamReassembler::StreamReassembler(const size_t capacity) : _output(capacity), _capacity(capacity), 
                                                              _stream(capacity), _cur_index(0),
                                                              _eof_index(std::numeric_limits<size_t>::max()), 
                                                              _unassembled_bytes_cnt(0) {}

//! \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) {
    auto st = max(index, _cur_index);
    auto ed = min(index + data.size(), min(_cur_index + _capacity - _output.buffer_size(), _eof_index));
    if (eof) _eof_index = min(_eof_index, index + data.size());
    for (size_t i = st, j = st - index; i < ed; ++i, ++j) {
        auto &t = _stream[i % _capacity];
        if (t.second == true) {
            if (t.first != data[j])
                throw runtime_error("StreamReassembler::push_substring: Inconsistent substrings!");
        } else {
            t = make_pair(data[j], true);
            ++_unassembled_bytes_cnt;
        }
    }
    string str;
    while (_cur_index < _eof_index && _stream[_cur_index % _capacity].second == true) {
        str.push_back(_stream[_cur_index % _capacity].first);
        _stream[_cur_index % _capacity] = { 0, false };
        --_unassembled_bytes_cnt, ++_cur_index;
    }
    _output.write(str);
    if (_cur_index == _eof_index) _output.end_input();
}

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

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

测试

std::map 版本

image-20230708195609081

std::vector 版本

image-20230708202639290

评论

  1. eightclound
    Windows Edge 116.0.1938.76
    6月前
    2023-9-13 22:25:03

    哥们问一下 是不是lab1及以后的lab都要克隆下来然后回滚一次 = =

  2. yoo2i
    Windows Edge 118.0.2088.76
    4月前
    2023-11-01 11:23:05

    老哥,我在合并lab1-startercode的时候报了个错,说是自动合并遇到了冲突,冲突在tests/CMakeLists.txt里面,你遇到过这个情况吗?(lab1-startercode难道需要什么其他操作才能正常合并吗)

    • 博主
      yoo2i
      Windows Chrome 118.0.0.0
      4月前
      2023-11-01 13:08:16

      不改动 CMakeLists.txt 就不会发生冲突

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇