CS144 计算机网络 Lab1:Stream Reassembler

这篇具有很好参考价值的文章主要介绍了CS144 计算机网络 Lab1:Stream Reassembler。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

上一篇博客中我们完成了 Lab0,使用双端队列实现了一个字节流类 ByteStream,可以向字节流中写入数据并按写入顺序读出数据。由于网络环境的变化,发送端滑动窗口内的数据包到达接收端时可能失序,所以接收端收到数据之后不能直接写入 ByteStream 中,而是应该缓存下来并按照序号重组成正确的数据。这篇博客所介绍的 Lab1 将实现一个字节流重组器 StreamReassambler 来完成上述任务。

CS144 计算机网络 Lab1:Stream Reassembler

实验要求

接收方的数据情况如下图所示,蓝色部分表示已消费的数据,绿色表示已正确重组但是还没消费的数据,红色则是失序到达且还没重组的数据:

CS144 计算机网络 Lab1:Stream Reassembler

由于接收端缓冲区大小 capacity 有限,超出容量的数据(first unacceptable 之后的数据)将被丢弃,这些被丢弃的数据包将起到流量控制的作用,可以限制发送端滑动窗口的大小。

流重组器的接口如下所示:

StreamReassembler(const size_t capacity);

//! \brief Receives a substring and writes any newly contiguous bytes into the stream.
//!
//! If accepting all the data would overflow the `capacity` of this
//! `StreamReassembler`, then only the part of the data that fits will be
//! accepted. If the substring is only partially accepted, then the `eof`
//! will be disregarded.
//!
//! \param data the string being added
//! \param index the index of the first byte in `data`
//! \param eof whether or not this segment ends with the end of the stream
void push_substring(const std::string &data, const uint64_t index, const bool eof);

//! 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
size_t unassembled_bytes() const;

//! Is the internal state empty (other than the output stream)?
bool empty() const;

其中最重要的函数就是 StreamReassambler::push_substring(),接收方收到数据之后就会调用此函数将数据保存起来。此函数接受三个参数:

  • data: 接收到的数据
  • index: 数据的第一个字节的索引,由于原始数据可能很大,超过了 TCPSegment 的容量,所以会将原始数据切分成多个片段,每个片段的第一个字节的索引就是 index,最小值为 0。请注意,这个 index 是流索引,不是报文段包头上的那个序列号,二者的关系将在 Lab2 中指出。
  • eof:是不是最后一个数据包

三个参数中,最耐人寻味的就是 index 参数,如果只是单纯的失序到达,数据之间没有发生重叠,Lab1 就比较好做了,但是实验指导书中明确指出

May substrings overlap? Yes

这就比较难搞了,因为重叠分成两种:

  1. 前面一部分与已重组的数据发生重叠
    CS144 计算机网络 Lab1:Stream Reassembler

  2. 前面不与已重组的数据发生重叠

    CS144 计算机网络 Lab1:Stream Reassembler

实际上由于 data 的末尾可能超出 first unacceptable,需要对超出部分进行截断,这可能导致 eof 标志失效,但是问题不大,发送方之后会重新发送这个数据包。

代码实现

为了处理上述重叠情况,需要一个 _next_index 成员代表 first unassembled 索引,一个 _unassembles 双端队列代表 first unassembledfirst unacceptable 之间的数据,由于里面可能只有一部分数据是有效的,所以用一个遮罩 _unassembled_mask 指出哪些数据是有效但是还没重组的。

class StreamReassembler {
  private:
    ByteStream _output;  //!< The reassembled in-order byte stream
    size_t _capacity;    //!< The maximum number of bytes
    std::deque<char> _unassembles{};
    std::deque<bool> _unassemble_mask{};
    size_t _unassambled_bytes{0};
    uint64_t _next_index{0};
    bool _is_eof{false};

    /** @brief 将数据写入未重组队列中
     * @param data 将被写入的字符串
     * @param dstart 字符串开始写入的位置
     * @param len 写入的长度
     * @param astart 队列中开始写入的位置
     */
    void write_unassamble(const std::string &data, size_t dstart, size_t len, size_t astart);

    /** @brief 重组数据
     */
    void assemble();

  public:
    StreamReassembler(const size_t capacity);

    //! \brief Receives a substring and writes any newly contiguous bytes into the 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
    size_t unassembled_bytes() const;

    bool empty() const;
};

收到数据时,先将不重叠的数据写入 _unassembles 队列中,之后调用 StreamReassabler::assemble() 函数重组队列中的连续数据,并更新 _next_index

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

//! \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 (index > _next_index + _capacity)
        return;

    if (eof)
        _is_eof = true;

    if (_is_eof && empty() && data.empty()) {
        _output.end_input();
        return;
    }

    auto end_index = data.size() + index;

    // 新数据在后面
    if (index >= _next_index) {
        auto astart = index - _next_index;
        auto len = min(_output.remaining_capacity() - astart, data.size());
        if (len < data.size())
            _is_eof = false;

        write_unassamble(data, 0, len, astart);
    }
    // 新数据与已重组的数据部分重叠
    else if (end_index > _next_index) {
        auto dstart = _next_index - index;
        auto len = min(_output.remaining_capacity(), data.size() - dstart);
        if (len < data.size() - dstart)
            _is_eof = false;

        write_unassamble(data, dstart, len, 0);
    }

    // 最后合并数据
    assemble();
    if (_is_eof && empty())
        _output.end_input();
}

void StreamReassembler::write_unassamble(const string &data, size_t dstart, size_t len, size_t astart) {
    for (size_t i = 0; i < len; ++i) {
        if (_unassemble_mask[i + astart])
            continue;

        _unassembles[i + astart] = data[dstart + i];
        _unassemble_mask[i + astart] = true;
        _unassambled_bytes++;
    }
}

void StreamReassembler::assemble() {
    string s;
    while (_unassemble_mask.front()) {
        s.push_back(_unassembles.front());
        _unassembles.pop_front();
        _unassemble_mask.pop_front();
        _unassembles.push_back('\0');
        _unassemble_mask.push_back(false);
    }

    if (s.empty())
        return;

    _output.write(s);
    _next_index += s.size();
    _unassambled_bytes -= s.size();
}

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

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

在命令行中输入:

cd build
make -j8
make check_lab1

可以看到测试用例也全部通过了:

CS144 计算机网络 Lab1:Stream Reassembler

调试代码

由于使用代码编辑器的是 VSCode,所以这里给出在 VSCode 中调试项目代码的方式。

tasks.json

首先在项目目录下创建 .vscode 文件夹,并新建一个 tasks.json 文件,在里面写入下述内容:

{
    "tasks": [
        {
            "type": "shell",
            "label": "cmake",
            "command": "cd build && cmake .. -DCMAKE_BUILD_TYPE=Debug",
            "detail": "CMake 生成 Makefile",
            "args": [],
            "problemMatcher": "$gcc"
        },
        {
            "type": "shell",
            "label": "build",
            "command": "cd build && make -j8",
            "detail": "编译项目",
            "args": [],
            "problemMatcher": "$gcc"
        },
    ],
    "version": "2.0.0"
}

这里主要配置了两个任务,一个调用 CMake 生成 Makefile,一个编译 Makefile。在 VSCode 中按下 Alt + T + R,就能在任务列表中看到这两个任务,点击之后就能执行。

CS144 计算机网络 Lab1:Stream Reassembler

launch.json

.vscode 文件夹中新建 launch.json,并写入下述内容:

{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "name": "debug lab test",
            "type": "cppdbg",
            "request": "launch",
            "program": "${workspaceFolder}/build/tests/${fileBasenameNoExtension}",
            "args": [],
            "stopAtEntry": false,
            "cwd": "${workspaceFolder}",
            "environment": [],
            "externalConsole": false,
            "MIMode": "gdb",
            "setupCommands": [
                {
                    "description": "Enable pretty-printing for gdb",
                    "text": "-enable-pretty-printing",
                    "ignoreFailures": true
                }
            ],
            "miDebuggerPath": "/usr/bin/gdb"
        },
        {
            "name": "debug current file",
            "type": "cppdbg",
            "request": "launch",
            "program": "${fileDirname}/${fileBasenameNoExtension}",
            "args": [],
            "stopAtEntry": false,
            "cwd": "${workspaceFolder}",
            "environment": [],
            "externalConsole": false,
            "MIMode": "gdb",
            "setupCommands": [
                {
                    "description": "Enable pretty-printing for gdb",
                    "text": "-enable-pretty-printing",
                    "ignoreFailures": true
                }
            ],
            "preLaunchTask": "C/C++: g++ build active file",
            "miDebuggerPath": "/usr/bin/gdb"
        }
    ]
}

之后打开一个测试用例,比如 tests/fsm_stream_reassembler_seq.cc,转到 debug 标签页,在代码中打下断点, 点击绿色按钮就能开始调试了:

CS144 计算机网络 Lab1:Stream Reassembler

调试效果如下图所示:

CS144 计算机网络 Lab1:Stream Reassembler

后记

通过这次实验,可以加深对接收端数据重组和分组序号的了解,期待后面的几个实验,以上~~文章来源地址https://www.toymoban.com/news/detail-419780.html

到了这里,关于CS144 计算机网络 Lab1:Stream Reassembler的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 北京大学计算机网络lab1——MyFTP

    目录 Lab目标 一、知识补充 二、具体实现 1.数据报文格式和字符串处理 2.open函数 3.auth 4.ls 5.get和put 三、总结 ps:本人靠着计网lab几乎就足够在就业行情并不好的23年找到自己满意的工作了,计网lab的教程也非常给力,对我这种恐惧写lab的菜狗都非常友好(本人写lab3确实比较

    2024年02月07日
    浏览(47)
  • CS144--Lab1笔记

    CS144——Lab1笔记 作为使用了版本管理的项目,开始新的开发,当然先要新建一个开发分支啦,可以用命令或者直接在IDE中GIT的图形控制界面操作,太简单就不细说。(我习惯命名:dev-lab1) 首先要从原始仓库合并Lab1的相关文件到本地仓库,接着在build目录下编译。执行下面的

    2024年02月20日
    浏览(51)
  • CS 144 Lab Four 收尾 -- 网络交互全流程解析

    对应课程视频: 【计算机网络】 斯坦福大学CS144课程 本节作为Lab Four的收尾,主要带领各位来看看网络交互的整体流程是怎样的。 这里以tcp_ipv4.cc文件为起点,来探究一下cs144是如何实现整个协议栈的。 首先,项目根路径中的 tun.sh 会使用 ip tuntap 技术创建虚拟 Tun/Tap 网络设备

    2024年02月04日
    浏览(41)
  • 《计算机网络自顶向下》Wireshark实验 Lab4 TCP

    《计算机网络自顶向下》Wireshark Lab + 套接字编程作业 + 杂项实验室编程作业 全实验博客链接 各位好 啊 学计算机想要学好真的还是挺难的 说实话 科班学计算机如果想要花大量的时间去学 只能把平时的课程大部分时间不去上 如果班级管理严格或者说 各种因素让你不得不去上

    2023年04月09日
    浏览(70)
  • Wireshark TCP实验—Wireshark Lab: TCP v7.0(计算机网络自顶向下第七版)

    What is the IP address and TCP port number used by the client computer (source) that is transferring the file to gaia.cs.umass.edu? 根据数据包中的 tcp-ethereal-trace-1 ,其源 IP 地址为 192.168.1.102 192.168.1.102 192.168.1.102 ,端口号为 1162 1162 1162 。 What is the IP address of gaia.cs.umass.edu? On what port number is it sending and re

    2023年04月09日
    浏览(42)
  • Wireshark IP实验—Wireshark Lab: IP v7.0(计算机网络自顶向下第七版)

    修改发送数据包的大小 跟踪的地址为 www.ustc.edu.cn text{www.ustc.edu.cn} www.ustc.edu.cn 由于自己抓的包比较凌乱,分析起来比较复杂,所以使用作者的数据包进行分析 Select the first ICMP Echo Request message sent by your computer, and expand the Internet Protocol part of the packet in the packet details window.Wh

    2024年02月04日
    浏览(36)
  • Wireshark HTTP实验—Wireshark Lab: HTTP v7.0(计算机网络自顶向下第七版)

    Is your browser running HTTP version 1.0 or 1.1? What version of HTTP is the server running? 浏览器与服务器的版本均为 H T T P / 1.1 HTTP/1.1 H TTP /1.1 。 What languages (if any) does your browser indicate that it can accept to the server? 能接受简体中文以及英文。 What is the IP address of your computer? Of the gaia.cs.umass.edu serv

    2024年02月08日
    浏览(37)
  • CS144-Lab6

    在本周的实验中,你将在现有的 NetworkInterface 基础上实现一个IP路由器,从而结束本课程。路由器有几个网络接口,可以在其中任何一个接口上接收互联网数据报。路由器的工作是根据 路由表 转发它得到的数据报:一个规则列表,它告诉路由器,对于任何给定的数据报: 发

    2024年02月09日
    浏览(43)
  • CS 144 Lab One -- 流重组器

    对应课程视频: 【计算机网络】 斯坦福大学CS144课程 Lab 1 对应的PDF: Lab Checkpoint 1: stitching substrings into a byte stream 这幅图完整的说明了CS144 这门实验的结构: 其中, ByteStream 是我们已经在 Lab0 中实现完成的。 我们将在接下来的实验中分别实现: Lab1 StreamReassembler :实现一个流

    2024年02月16日
    浏览(39)
  • CS 144 Lab Four -- the TCP connection

    对应课程视频: 【计算机网络】 斯坦福大学CS144课程 Lab Four 对应的PDF: Lab Checkpoint 4: down the stack (the network interface) TCPConnection 需要将 TCPSender 和 TCPReceiver 结合,实现成一个 TCP 终端,同时收发数据。 TCPConnection 有几个规则需要遵守: 对于 接收数据段 而言: 如果接收到的数据包

    2024年02月13日
    浏览(32)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包