【计算机网络】CS144 Lab 1:将子串拼接成字节流

一、概述

实验作业将要求我们以模块化的方式构建TCP实现:
1.在实验1中,我们将实现一个流重组器,该模块将字节流的小段(称为子字符串或段)重组回正确序列的连续字节流。
2.在实验2中,我们将实现处理入站字节流的TCP部分: TCPReceiver。这涉及到TCP将如何表示每个字节在流中被称为\序列号的|中的位置。”tcprecreceiver负责告诉发送方(a)它已经成功组装了多少入站字节流(这叫做\确认”)和(b)发送方现在还允许发送多少字节(\流控制”)
3.在实验3中,我们将实现处理输出字节流的TCP部分:
TCPSender。当发送方怀疑它传输的一个片段在途中丢失了,没有到达接收方时,它应该如何反应?它应该在什么时候再次尝试并重新发送丢失的片段?
4.在实验4中,我们将结合以前的工作和实验的工作来创建一个工作
TCP实现:一个包含TCPSender和TCPReceiver的TCPConnection。
我们将使用它与世界各地的真实服务器进行通信。

二、开始

在sponge目录下运行

git fetch
git merge origin/lab1-startercode

得到lab1的源码
在build目录下make

三、按顺序放置子字符串

TCP发送方将其字节流分成较短的段(每个子串不超过1460个字节),以便每个子串都能装入一个数据报中。但是网络可能会对这些数据报进行重新排序,或者丢弃它们,或者多次发送它们。接收端必须将这些段重新组装成它们开始时的连续字节流。
在本实验中,我们将实现一个流重组器(stream reassembler),可以将带索引的字节流碎片重组成有序的字节流。重组完的字节流应当被送入指定的字节流(byte stream)对象_output中。

分析:

	//! \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);

接收子串,并将新的连续的字节写入流中。只写入新的,如果有重合部分则丢弃重合部分。这里也要注意容量,超出容量部分要丢弃。
data:子串内容
index:’ data '中第一个字节的索引(按顺序排列)
eof:data的最后一个字节是否为整个流的最后一个字节

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

重组器是否为空

3.1 FAQs

1.整个流中第一个字节的索引是什么?零。
2.我的实现应该有多高效?我们不打算指定一个特定的概念的效率,但请不要把这作为一个挑战来构建一个空间或时间低效的数据结构,这个数据结构将是您的TCP实现的基础。
3.应该如何处理不一致的子字符串?你可以假设它们不存在。也就是说,您可以假设存在一个惟一的底层字节流,并且所有的子字符串都是它的(准确的)片段
4.我可以用什么?您可以使用标准库中任何您认为有用的部分。特别是,我们希望您至少使用一种数据结构。
5.什么时候应该将字节写入流?越快越好。一个字节不应该出现在流中的唯一情况是,在它之前有一个字节还没有被推入。
6.子重叠吗?是的。
7.我是否需要向StreamReassembler添加私有成员?是的。由于段可能以任何顺序到达,你的数据结构将不得不记住“子字符串,直到它们准备放入流“,也就是说,直到它们之前的所有索引都被填满。

以下参考segmentfault
注意点:

  • 报文段包含索引、长度、内容,lab1 的索引从 0 开始增长,不会溢出绕回。
  • 任何报文段,包括新收到的和暂存的,只要可以,就应该立刻送入 ByteStream(可能需要手动重组和去重叠)。
  • 容量的限制如下图所示。
    在这里插入图片描述

思路:

流重组器首先要选择一个数据结构,要储存:data、首索引、长度,使用结构体

接收子串:超过容量的部分丢弃,剩下的丢给重叠处理

重叠处理:前面部分重叠、后面部分重叠、两者都有、两者都无,合并两个子串

已存储但未被重组的字节流数:需要三个变量存储:最早未读、最早未被重组、最早未被接收。后两个坐标之间的子串长度相加

重组器是否为空:变量_is_end存储字节流是否到达结尾,如果字节流到达结尾并且重组器为空,则返回是

根据FAQs5,还需要一个函数,将重组好的片段送入ByteStream

代码:
.hh

class StreamReassembler {
   
  private:
    // Your code here -- add private members as necessary.

    ByteStream _output;  //!< The reassembled in-order byte stream. ByteStream类,实现名为_output
    size_t _capacity;    //!< The maximum number of bytes
    size_t _first_unread = 0;//最早未读的下标
    size_t _first_unassembled = 0;//最早未重组的下标
    size_t _first_unacceptable;//最早未被接收的下标
    bool _eof = false;//字符流是否全部被重组完(到达结尾)
    struct seg {
   //定义seg结构:首字节的index;子串长度;子串内容;重载运算符<
        size_t index;
        size_t length;
        std::string data;
        bool operator<(const seg t) const {
    return index < t.index; }
    };
    std::set<seg> _stored_segs = {
   };//实现seg结构:已被存储的子串

    void _add_new_seg(seg &new_seg, const bool eof);//添加新段
    void _handle_overlap(seg &new_seg);//处理重叠部分
    void _stitch_output();//将重组好的所有段送入ByteStream
    void _stitch_one_seg(const seg &new_seg);//将重组好的某一段送入ByteStream中
    void _merge_seg(seg &new_seg
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值