Stanford CS144: Lab 1

1 介绍

在链路层,由传输介质的物理特性决定了数据帧的长度。

以以太网为例,链路层一个数据帧最大为 1518Byte,首部长18Byte,IP层首部长20Byte,传输层 UDP首部长 8Byte,TCP首部长 20Byte。因此TCP包的数据内容最大为 1460 Byte。

而传输数据方的数据是很可能大于1460的,所以会拆分成多个数据包,因此Receiver需要去实现数据包的Reassembler,而这就是lab 1需要完成的内容。

在这里插入图片描述

Capacity

PDF中强调了capacity的含义:

capacity表示了整个Reassembler可以存放的数据流的大小,这个数据流包括 ByteStream 以及 缓存的数据流。

所以之前lab0中采用string当作ByteStream当作底层数据结构就不再合适了,因此改为 deque。比较简单,就不贴代码了。

2 添加成员

  • 添加了一个内部类, 这个类是用来存放还未写入ByteStream的数据。其中对 操作符 < 进行了重载,用于set的排序。
  • _nowIndex:用来表示需要发送者发来的str的index值。
  • _inorderedStr:用set去装缓存的str。
  • _output:读写的流。
  • _capacity:容量。
  • _sizeOfUnassembledBytes:set中str的数据量之和。
  • remaining_capacity():剩余容量。
  • merge_inorderedStr():将新的Str放入set,并处理合并以及删除的逻辑。
// stream_reassembler.hh

private:
    // Your code here -- add private members as necessary.
    class StoreSubstr{
      public:
        std::string _data{};
        size_t _index{};
        bool _eof{};

        StoreSubstr(std::string data,const size_t index,const bool eof){
            _data = std::move(data);
            _index = index;
            _eof = eof;
        }
        bool operator < (const StoreSubstr &b) const{
            return _index == b._index ? _index + _data.size() < b._index + b._data.size() : _index < b._index;
        }
    };

    size_t _nowIndex{};    //!< The index needed now
    std::set<StoreSubstr> _inorderedStr{};    //!< Store the inordered substr
    std::set<size_t>   _indexIn{};               //!< Represent the index in the storage
    ByteStream _output;  //!< The reassembled in-order byte stream
    size_t _capacity{};    //!< The maximum number of bytes
    size_t _sizeOfUnassembledBytes{};

    size_t remaining_capacity() const;
    
    //!< Insert the new Str in the storage
    void merge_inorderedStr(const std::string &data, const uint64_t index, const bool eof);

3 接口的实现

实现的主要逻辑都在 merge_inorderedStr()里面。这些接口的内容都很简单,除了push_substring中会有部分简单处理。

push_substring() 先是预处理data,处理完之后就调用merge_inorderedStr(),然后再进行write写入。

StreamReassembler::StreamReassembler(const size_t capacity) : _output(capacity), _capacity(capacity) {
    _nowIndex = 0;
    _sizeOfUnassembledBytes = 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) {
    // If the data has been writen in,just discard it,
    // and we will accept index + data.size() == _nowIndex,
    // because it may carry the info about eof.
    if(index + data.size() < _nowIndex)
        return;

    std::string newStr,ttp;
    size_t newIndex;

    ttp = data;

    // If the index < _nowIndex,truncate the str
    if(index < _nowIndex){
        newStr = data.substr(_nowIndex-index);
        newIndex = _nowIndex;
    }
    else{
        newStr = data;
        newIndex = index;
    }


    merge_inorderedStr(newStr,newIndex,eof);

    // If the first str can be write in.
    // Because the eof may cause the break part.
    while(!_inorderedStr.empty() && _inorderedStr.begin()->_index == _nowIndex){
        auto it = _inorderedStr.begin();

        _output.write(it -> _data);
        if(it -> _eof){
            _output.end_input();
        }

        _nowIndex = it -> _index + it -> _data.size();
        _sizeOfUnassembledBytes -= it -> _data.size();
        _inorderedStr.erase(it);
    }
    
}

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

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

size_t StreamReassembler::remaining_capacity() const{
    return _output.remaining_capacity() - _sizeOfUnassembledBytes;
}

4 merge_inorderedStr()

merge需要考虑的问题:

  • 插入后超出capacity。
    • 需要删除最后面部分,来满足capacity。
  • 插入的合并问题。
  • 数据的重复问题。

实现逻辑:

  • 直接插入新的StoreSubstr,然后找到它的位置。
  • 考虑其是否会合并到前一个StoreSubstr,如果会的话,就从前一个开始。
  • 新建一个新StoreSubstr来存储合并后的内容。
  • 复制完毕后,删除原StoreSubstr,插入新的StoreSubstr。这边要特别注意到 长度为0的eof的情况。
  • 检查是否超出capacity,如果超出就从后面往前面删。
void merge_inorderedStr(const std::string &data, const uint64_t index, const bool eof){
        StoreSubstr tmp = StoreSubstr(data,index,eof);
        _inorderedStr.insert(tmp);
        _sizeOfUnassembledBytes += data.size();

        auto it = _inorderedStr.find(tmp);
        size_t la = 0;
        std::string str;
        uint64_t newIndex;
        bool newEof = false;

        // merge front one
        if(it != _inorderedStr.begin()){
            it--;
            if(it->_index + it->_data.size() <= index)
                it++;
        }
        newIndex = it->_index;
        // for erase
        auto beg = it;

        while(true){
            // copy to new str
            la = std::max(it->_index + it->_data.size(),la);
            for(size_t i = newIndex + str.size() - it->_index;i < it->_data.size();i++)
                str.push_back(it->_data[i]);

            _sizeOfUnassembledBytes -= it->_data.size();
//        if(it->_eof){
//            // [begin,end)
//            it++;
//            newEof = true;
//            break;
//        }
            newEof = it->_eof;

            it++;
            // If not continuous,break;
            if(it->_index > la || (it -> _index == la && it ->_data.size() == 0))
                break;
        }
        // erase the merged ones
        _inorderedStr.erase(beg,it);

        _inorderedStr.insert(StoreSubstr(str,newIndex,newEof));
        _sizeOfUnassembledBytes += str.size();

        // delete the oversize part
        while(_output.remaining_capacity() < _sizeOfUnassembledBytes){
            size_t oversize = _sizeOfUnassembledBytes - _output.remaining_capacity();
            it = _inorderedStr.cbegin();

            // If it is enough,delete part of it
            if(it -> _data.size() > oversize){
                size_t oriSize = it->_data.size();
                std::string tmp_val = it -> _data.substr(0,oriSize - oversize);
                _inorderedStr.insert(StoreSubstr(tmp_val,it->_index,false));
                _sizeOfUnassembledBytes -= oversize;
                _inorderedStr.erase(it);
            }
                // else delete it;
            else{
                _sizeOfUnassembledBytes -= it->_data.size();
                _inorderedStr.erase(it);
            }
        }
    }

tr.erase(it);
}
// else delete it;
else{
_sizeOfUnassembledBytes -= it->_data.size();
_inorderedStr.erase(it);
}
}
}


![在这里插入图片描述](https://img-blog.csdnimg.cn/d6a4174f9ea844cfafdd610b5c46a071.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzE3NDQ3Nw==,size_16,color_FFFFFF,t_70#pic_center)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值