CS 144 Lab Zero -- 可靠的内存字节流

news2025/1/4 15:55:07

CS 144 Lab Zero -- 可靠的内存字节流

  • 环境搭建
  • 使用socket写一个网络程序
  • In-memory reliable byte stream


对应课程视频: 【计算机网络】 斯坦福大学CS144课程

Lab 0 对应的PDF: Lab Checkpoint 0: networking warmup

Lab 0 会省去Telnet部分内容。


环境搭建

  • Run Ubuntu version 22.10, then install the required packages:
sudo apt update && sudo apt install git cmake gdb build-essential clang \
clang-tidy clang-format gcc-doc pkg-config glibc-doc tcpdump tshark

使用socket写一个网络程序

在IP层,数据包传输的原则是“best-effort”,即尽最大努力传输数据包,但不保证一定送达。数据包可能会丢失、重传、出错、乱序到达。把这种混乱的数据包变成可靠的字节流,则是TCP传输层的责任。

本节我们将写一个“webget”程序,创建一个TCP stream socket,去和一个web server建立连接。你可以认为你的socket是一个双向的可靠的字节流传输服务,这种可靠性是TCP协议所保证的。

git clone https://gitee.com/DaHuYuXiXi/cs144.git

cd cs144-sponge
mkdir build
cd build

cmake ..
make

实验指导书建议我们使用Modern C++的特性,来写这个实验。并建议我们使用git来管理项目。

建议仔细阅读一下文档:

  1. https://cs144.github.io/doc/lab0
  2. FileDescriptor, Socket, TCPSocket, and Address classes

各个类的继承关系如下:

在这里插入图片描述
看上去比较重要的是TCPSocket这个类,读完文档之后,我们就可以去实现webget程序了,代码量预计 10 行左右,位于apps/webget.cc,实现代码时务必借助 libsponge 中的 TCPSocketAddress 类来完成。

需要注意的是

  • HTTP 头部的每一行末尾都是以\r\n结尾,而不是\n

  • 需要包含Connection: close 的HTTP头部,以指示远程服务器在处理完当前请求后直接关闭。

  • 除非获取到EOF,否则必须循环从远程服务器读取信息。

  • 因为网络数据的传输可能断断续续,需要多次 read。

具体代码实现如下:

void get_URL(const string &host, const string &path) {
    // You will need to connect to the "http" service on
    // the computer whose name is in the "host" string,
    // then request the URL path given in the "path" string.

    // Then you'll need to print out everything the server sends back,
    // (not just one call to read() -- everything) until you reach
    // the "eof" (end of file).
    TCPSocket socket;
    socket.connect(Address(host, "http"));
    // message template
    string messages;
    messages += "GET " + path + " HTTP/1.1\r\n";
    messages += "Host: " + host + "\r\n";
    messages += "Connection: close\r\n\r\n";
    // write message
    socket.write(messages);
    cout << "Message: \r" << messages;
    while (!socket.eof()) {
        cout << socket.read();
    }
    socket.close();
}

实现完之后,在/biuld目录下,构建,并运行

make
./apps/webget cs144.keithw.org /hello

它的行为应该和上述2.1小节的行为保持一致。

最后它应该能够通过测试

make check_webget

在这里插入图片描述


In-memory reliable byte stream

要求

  • 字节流可以从写入端写入,并以相同的顺序,从读取端读取
  • 字节流是有限的,写者可以终止写入。而读者可以在读取到字节流末尾时,产生EOF标志,不再读取。
  • 所实现的字节流必须支持流量控制,以控制内存的使用。当所使用的缓冲区爆满时,将禁止写入操作。直到读者读取了一部分数据后,空出了一部分缓冲区内存,才让写者写入。
  • 写入的字节流可能会很长,必须考虑到字节流大于缓冲区大小的情况。即便缓冲区只有1字节大小,所实现的程序也必须支持正常的写入读取操作。

在单线程环境下执行,因此不用考虑各类条件竞争问题。

这是在内存中的有序可靠字节流,接下来的实验会让我们在不可靠网络中实现一个这样的可靠字节流,而这便是传输控制协议(Transmission Control Protocol,TCP)

以下是实现的代码:

  • byte_stream.hh
#include <deque>
#include <string>
#include <vector>

//!  An in-order byte stream.

//! Bytes are written on the "input" side and read from the "output"
//! side.  The byte stream is finite: the writer can end the input,
//! and then no more bytes can be written.
class ByteStream {
  private:
    // Your code here -- add private members as necessary.

    // Hint: This doesn't need to be a sophisticated data structure at
    // all, but if any of your tests are taking longer than a second,
    // that's a sign that you probably want to keep exploring
    // different approaches.

    std::deque<char> buffer_;
    size_t capacity_;
    bool is_ended_, is_eof_;
    size_t bytes_written_, bytes_read_;

    bool _error{};  //!< Flag indicating that the stream suffered an error.

  public:
    //! Construct a stream with room for `capacity` bytes.
    ByteStream(const size_t capacity);
    //! Write a string of bytes into the stream. Write as many
    //! as will fit, and return how many were written.
    size_t write(const std::string &data);
    //! Write one character into the stream.
    bool write_char(char datum);
    //! \returns the number of additional bytes that the stream has space for
    size_t remaining_capacity() const;
    //! Signal that the byte stream has reached its ending
    void end_input();
    //! Indicate that the stream suffered an error.
    void set_error() { _error = true; }
    //! Peek at next "len" bytes of the stream
    std::string peek_output(const size_t len) const;
    //! Remove bytes from the buffer
    void pop_output(const size_t len);
    //! Read (i.e., copy and then pop) the next "len" bytes of the stream
    std::string read(const size_t len);
    //! \returns `true` if the stream input has ended
    bool input_ended() const;
    //! \returns `true` if the stream has suffered an error
    bool error() const { return _error; }
    //! \returns the maximum amount that can currently be read from the stream
    size_t buffer_size() const;
    //! \returns `true` if the buffer is empty
    bool buffer_empty() const;
    //! \returns `true` if the output has reached the ending
    bool eof() const;
    //! Total number of bytes written
    size_t bytes_written() const;
    //! Total number of bytes popped
    size_t bytes_read() const;
};
  • byte_stream.cc
#include "byte_stream.hh"

#include <iostream>

// Dummy implementation of a flow-controlled in-memory byte stream.

// For Lab 0, please replace with a real implementation that passes the
// automated checks run by `make check_lab0`.

// You will need to add private members to the class declaration in
// `byte_stream.hh`

using namespace std;

ByteStream::ByteStream(const size_t capacity)
    : buffer_()
    , capacity_(capacity)
    , is_ended_(false)
    , is_eof_(false)
    , bytes_written_(0)
    , bytes_read_(0)
    , _error(false) {}

size_t ByteStream::write(const string &data) {
    size_t write_amount = remaining_capacity() < data.length()
                              ? remaining_capacity()
                              : data.length();  // min(remaining_capacity(), data.length());
    for (size_t i = 0; i < write_amount; i++) {
        buffer_.push_back(data[i]);
    }
    bytes_written_ += write_amount;
    return write_amount;
}

bool ByteStream::write_char(char datum) {
    if (remaining_capacity() == 0)
        return false;
    buffer_.push_back(datum);
    bytes_written_++;
    return true;
}

//! \param[in] len bytes will be copied from the output side of the buffer
string ByteStream::peek_output(const size_t len) const {
    size_t peek_length = len < buffer_size() ? len : buffer_size();
    string out_string(peek_length, ' ');
    for (size_t i = 0; i < peek_length; i++) {
        out_string[i] = buffer_[i];
    }
    return out_string;
}

//! \param[in] len bytes will be removed from the output side of the buffer
void ByteStream::pop_output(const size_t len) {
    size_t pop_length = len < buffer_size() ? len : buffer_size();
    for (size_t i = 0; i < pop_length; i++)
        buffer_.pop_front();
    bytes_read_ += pop_length;
    if (is_ended_ && buffer_empty())
        is_eof_ = true;
}

//! Read (i.e., copy and then pop) the next "len" bytes of the stream
//! \param[in] len bytes will be popped and returned
//! \returns a string
std::string ByteStream::read(const size_t len) {
    string out = peek_output(len);
    pop_output(len);
    return out;
}

void ByteStream::end_input() {
    if (buffer_.empty())
        is_eof_ = true;
    is_ended_ = true;
}

bool ByteStream::input_ended() const { return is_ended_; }
size_t ByteStream::buffer_size() const { return buffer_.size(); }
bool ByteStream::buffer_empty() const { return buffer_.empty(); }
bool ByteStream::eof() const { return is_eof_; }
size_t ByteStream::bytes_written() const { return bytes_written_; }
size_t ByteStream::bytes_read() const { return bytes_read_; }
size_t ByteStream::remaining_capacity() const { return capacity_ - buffer_.size(); }

实现完之后,使用如下命令进行测试:

cd build
make
make check_lab0 

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/775816.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

模拟算法leetcode刷题

1)替换所有的问号: 1)模拟算法流程&#xff0c;一定要在草稿纸上过一遍流程 2)将流程转化成代码 1576. 替换所有的问号 - 力扣&#xff08;Leetcode&#xff09; class Solution {public String modifyString(String s) {char[] arrays.toCharArray();for(int i0;i<array.le…

去掉回车和换行符

1.工具用notePad 把Linux 等环境下的日志打印出来的sql 复制出来时包含换行符和回车符&#xff0c;无法直接在数据库客户端工具直接执行&#xff0c;需要去掉换行符和回车符。使用notepad 中的替换功能批量替换回车符和换行符。

6. 测试的分类以及黑盒测试、白盒测试和黑盒测试的区别

目录 1. 按照测试对象划分 1.1 界面测试 1.2 可靠性测试 1.3 容错性测试 1.5 兼容性测试 1.6 易用性测试 1.7 安装卸载测试 1.8 安全性测试 1.9 性能测试 1.10 内存泄漏测试 2. 按是否查看代码划分 2.1 黑盒测试&#xff08;Black-box Testing&#xff09; 优点 …

在 IDEA 中使用 Git 图文教程

Git 专栏索引&#xff1a; Git 分布式版本控制系统使用教程 在 IDEA 中使用 Git 图文教程 在 IDEA 中使用 Git 图文教程 &#x1f680;1. 配置 Git&#x1f680;2. 创建项目远程仓库&#x1f680;3. 初始化本地仓库&#x1f680;4. 连接远程仓库&#x1f680;5. 提交到本地仓库…

Python(二十三)运算符——赋值运算符

❤️ 专栏简介&#xff1a;本专栏记录了我个人从零开始学习Python编程的过程。在这个专栏中&#xff0c;我将分享我在学习Python的过程中的学习笔记、学习路线以及各个知识点。 ☀️ 专栏适用人群 &#xff1a;本专栏适用于希望学习Python编程的初学者和有一定编程基础的人。无…

CityGML三维场景查看

今天我将展示如何读取 CityGML 文件并以 3D 方式查看其信息&#xff0c;以及如何通过挤出将shapefile转化为3D模型。 我还没有找到 3D 渲染器中可用设置的非常详细的描述&#xff0c;因此我花了一些时间测试它们。 我试图弄清楚它们的作用以及何时使用它们。 我将在本文末尾解…

英码积极参与行业交流活动,“快、易、省”赋能更多企业具备AI能力

2023年&#xff0c;ChatGPT的火爆引发了算力需求的大爆发&#xff0c;有人说&#xff0c;边缘计算因兼具时延低与安全等优势&#xff0c;或将成为解决AI算力紧张的良方&#xff1b;在人工智能产业发展的推动下&#xff0c;边缘计算成为了众人瞩目的焦点。随着应用场景的多元化和…

关于 华为云:服务器上传文件夹后显示403

问题原因&#xff1a; 华为云&#xff1a;当前使用的操作系统默认的umask 值是0027 上传文件后出现权限403 的问题&#xff1a; 解决1&#xff1a;修改 /etc/profile 文件 027 022 查看是否修改&#xff1a; 指令&#xff1a;umask 0022 需要删除之前的 文件重新上传&am…

【C语言】指针还不会?这一篇就够了

&#x1f466;个人主页&#xff1a;Weraphael ✍&#x1f3fb;作者简介&#xff1a;目前正在回炉重造C语言&#xff08;2023暑假&#xff09; ✈️专栏&#xff1a;【C语言航路】 &#x1f40b; 希望大家多多支持&#xff0c;咱一起进步&#xff01;&#x1f601; 如果文章对你…

HNU-计算机系统CS-学习感悟

本学期学的两门核心课&#xff0c;一个CS&#xff0c;一个OS。对我来说都有一定难度。 CS总评91/100。主要是期末考试没太发挥好&#xff0c; 主要原因是存储部分有个没有考虑写的情况&#xff0c;送了8分。 总领 CS的学习采用最经典的书——CSAPP&#xff0c;也被称为计算机…

vue3 ts vite electron开发桌面程序

1、搭建vuetsvite项目 # 创建Vue项目 npm init vue # 安装依赖 npm install # 一定要安装成开发依赖 npm install electron electron-builder -D 根目录创建plugins文件夹&#xff0c;文件夹中创建ts文件&#xff0c;vite.electron.build.ts是打包文件代码&#xff0c;v…

LeetCode面试题02.07.链表相交

面试题02.07.链表相交 两种解题思路 面试题02.07.链表相交一、双指针二、哈希集合 一、双指针 这道题简单来说&#xff0c;就是求两个链表交点节点的指针 这里注意&#xff1a;交点不是数值相等&#xff0c;而是指针相等 为了方便举例&#xff0c;假设节点元素数值相等&…

MySQL 坐标批量计算及优化

文章目录 1、坐标计算2、优化 现在有一个需求&#xff0c;就是找出距离某用户最近的一些点&#xff0c;一种实现方法就是调用地图的api来计算筛选&#xff0c;另外一种就是在数据库中计算&#xff0c;考虑到地图api有并发量限制&#xff0c;所以选用数据库计算的方式。 1、坐标…

Python实现HBA混合蝙蝠智能算法优化BP神经网络分类模型(BP神经网络分类算法)项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 蝙蝠算法是2010年杨教授基于群体智能提出的启发式搜索算法&#xff0c;是一种搜索全局最优解的有效方法…

成功升级scikit-image的版本,从老版本0.13.0到0.17.2

成功升级scikit-image的版本&#xff0c;从老版本0.13.0到0.17.2 之前参考其他博客升级scikit-image的版本没有成功&#xff0c;这次参考scikit-image的github官网&#xff0c;顺利实现了升级。 scikit-image的github官网中关于安装的介绍页 https://github.com/scikit-imag…

Dubbo入门实战最全攻略(基于 Spring Boot 实现)

Dubbo应用 RPC通信 Apache Dubbo 3构建在 HTTP/2 协议之上&#xff0c;具有更好的穿透性与通用性 &#xff0c; 支持基于 IDL 的服务定义 集成了业界主流的大部分协议&#xff0c;使得用户可以在 Dubbo 框架范围内使用这些通信协议 &#xff0c; 这些协议包括 rest、hessian…

【动态规划】三步问题

&#x1f9c1;题目描述&#xff1a; 示例&#xff1a; &#x1f9c0;(1)题目解析&#xff1a; 小孩每一次可以走1,2,3步&#xff0c;那么形成不同的排列组合&#xff0c;会有很多种上楼梯方式。 &#x1f9c0;(2)算法原理&#xff1a; &#x1f951;[1]状态表示 根据题目要…

【C++杂货铺】构造函数和析构函数

文章目录 一、类的六个默认成员函数二、构造函数三、析构函数 一、类的六个默认成员函数 &#x1f4d6;默认成员函数 用户没有显式实现&#xff0c;编译器会自动生成的成员函数&#xff0c;称为默认成员函数。 构造函数&#xff1a;完成对象的初始化工作。析构函数&#xff…

容器化时代的领航者:Docker 和 Kubernetes 云原生时代的黄金搭档

一、Docker docker是一种开源的应用容器引擎&#xff0c;可以将应用程序和依赖打包成一个可移植的镜像&#xff0c;然后发布到任何支持docker的平台上&#xff0c;也可以实现虚拟化。docker的核心概念有三个&#xff1a;镜像&#xff08;image&#xff09;、容器&#xff08;co…

QT中QTimer的循环时间与槽函数执行时间以及在事件循环中触发,不同时间的结果分析

目录 当循环时间小于槽函数时间时&#xff1a; 当循环间隔时间大于槽函数时间时&#xff1a; 当存在两个定时器器&#xff0c;其中一个还是间隔100ms&#xff0c;另一个间隔1000ms&#xff1a; 当两个定时器的循环周期大于槽函数执行时间时 当在主程序中添加一个for循环…