CS144-2021|Lab1 个人实验记录

185 阅读2分钟

lab1

参考Stanford CS144 Lab1 小结 - 知乎 (zhihu.com)

个人实验留档:cs144-2021

Overview

image.png

通过上面这个图,可以看到这个实验要做的部分:在tcp将数据报文传输过来时,由于报文会存在乱序、重复的问题,所以需要在接收端将报文排序成有序的数据报,然后在传输给在Lab0中的ByteStream

Putting substrings in sequence

对于传输过来的数据报,其拥有唯一的 index 标识其第一个字节在原始的、未被分割的数据中的位置。

传输过来的数据会出现重复、部分重叠问题,需要在实现过程中考虑。

image.png

上面这个图表示的是capacity的范围,即,capacity应该是byteStream中写入还没被读的容量(即byteStream中的队列容量)+ 未被重排的数据。

具体实现

这一部分存储unassembled的数据一开始打算使用map<size_t,string>的数据结构来进行存储,但是在实现过程中发现有太多情况比如子串重叠、重复等需要覆盖,面向测试用例编程但是最后也没有通过所有测试。最后放弃重新改为类似于lab1中使用deque来进行存储。

  • 私有变量设置
class StreamReassembler {
  private:
    // Your code here -- add private members as necessary.
    // index->(data, origin_data_size)
    std::deque<char> _unassembled_queue;
    std::deque<bool> _flags_queue; // 标记queue中的对应位置是否有数据
    bool _is_eof;
    size_t _eof_idx;
    size_t _unassembled_size;

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

//。。。。后面省略
  • 成员函数实现
StreamReassembler::StreamReassembler(const size_t capacity)
    : _unassembled_queue(capacity, '\0')
    , _flags_queue(capacity, false)
    , _is_eof(false)
    , _eof_idx(0)
    , _unassembled_size(0)
    , _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) {
    // substrings provided to the push substring() function may overlap
    size_t first_unassembled = _output.bytes_written();
    size_t first_unaccept = _output.bytes_read() + _capacity;

    // 处理那些在范围之外内的数据
    // 注意,有可能数据在范围之外,但是其 eof 标志位为1,因此,对于在范围之外的数据不能简单丢弃
    if (!(index >= first_unaccept || index + data.size() <= first_unassembled)) {
        size_t begin_idx = max(index, first_unassembled);
        size_t end_index = min(first_unaccept, index + data.size());

        // 将数据存放到 _unassembled_queue 中
        for (size_t i = begin_idx; i < end_index; i++) {
            if (!_flags_queue[i - first_unassembled]) {
                _unassembled_queue[i - first_unassembled] = data[i - index];
                _unassembled_size++;
                _flags_queue[i - first_unassembled] = true;
            }
        }

        // 将有序的数据写入 ByteStream
        string to_write = "";
        while (_flags_queue.front() && to_write.size() < _output.remaining_capacity()) {
            to_write += _unassembled_queue.front();
            _unassembled_queue.pop_front();
            _flags_queue.pop_front();
            // 入队占位,保持队列容量不变,类似滑动窗口
            _unassembled_queue.emplace_back('\0');
            _flags_queue.emplace_back(false);
        }

        if (to_write.size() > 0) {
            _unassembled_size -= to_write.size();
            _output.write(to_write);
        }
    }

    if (eof) {
        _eof_idx = index + data.size();
        _is_eof = true;
    }
    if (_is_eof && _eof_idx == _output.bytes_written()) {
        _output.end_input();
    }
}

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

bool StreamReassembler::empty() const { return unassembled_bytes() == 0; }class StreamReassembler {
  private:
    // Your code here -- add private members as necessary.
    std::deque<char> _unassembled_queue;
    std::deque<bool> _flags_queue;  // 标记是否有数据
    bool _is_eof;
    size_t _eof_idx;
    size_t _unassembled_size;

    ByteStream _output;  //!< The reassembled in-order byte stream
    size_t _capacity;    //!< The maximum number of bytes
  • 注意在实现时,对于不在范围内的数据不能立即return,因为此时参数中的eof标志位可能是有效的,因此需要更新eof_index。

测试

image.png

总结

这个实验在难度上不算难,重要的是如何实现、用什么样的数据结构以及对于边界条件的覆盖。