CS144 Lab:Lab0
本文最后更新于 49 天前,内容如有失效请评论区留言。

Lab0 首先有两个小实验热身,然后就是配置开发环境,熟悉实验环境,并实现 ByteStream

据了解,CS144 的 Lab 现在有两个大版本,一个是 Sponge 版本,一个是 Minnow,Sponge 是旧版本,也是大多数人完成实验的版本,8 个 Project 带你实现整个 TCP/IP 协议栈。而 Minnow 是 2023 年春季新上线的版本,新版本据说难度降低了,砍掉了原来最难的 TCP Connection 部分,内容也有所改动。为了更好的实验体验和学习资料,这里我还是选择经典 Sponge 版本来完成实验。

但一件遗憾的事是,新版本 Minnow 上线后旧版本 Sponge 的仓库被官方下线了,我们无法再直接获取到官方的 Sponge 最新仓库代码,只能从别人实验的 GitHub 仓库中回退来获取到原始实验代码,为此后面也踩了点坑和折腾了一下(因为 Git 技术太菜了)。

我的 CS144 代码仓库

Fetch a Web page

使用 telnet 发送 HTTP 报文获取网页内容

image-20230706124929756

一个坑点是步骤中没有说清楚成功要点:输入的速度一定要快

换句话说,只能复制粘贴下面的内容,而不是手动输入

GET /hello HTTP/1.1
Host: cs144.keithw.org
Conncetion: close

第二个热身 Send yourself an email 我没有做,因为文档上的步骤需要 Stanford 的邮箱

Listening and connecting

netcat 作为 server,telnet 作为 client,相互通信

image-20230706224245757

配置开发环境

实验环境需要 cmake, git 和最新的 g++,整个 Lab 采用 Modern C++ 作为开发语言,C++ 17 标准。(当然官网现在的 mirrow 版本的 Lab 已经是 C++ 20 标准了)

image-20230706235427409

竟然遇到了下面这个错误

image-20230707001119609

buffer.hh 中添加 #include <stdexcept> 就可以解决了(更新:后来换了一个貌似更新的实验仓库,直接就能编译通过了)

image-20230707001057010

编译安装 doxygen

image-20230707161940032

Webget

要求实现 get_URL 函数,功能为向指定 IP 地址发送 HTTP GET 请求,然后输出所有响应。

要求调用 Linux kernel 自带的 TCP/IP 协议栈实现即可,Sponge 已经将 C-Style 的 Socket 封装成了几个 C++ 类:FileDescriptor, Socket, TCPSocket, and Address classes。具体见官方文档

按照 HTTP 报文格式模拟发送 HTTP 报文即可实现

代码如下:

void get_URL(const string &host, const string &path) {
    // Your code here.

    // 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 sock;
    sock.connect(Address(host, "http"));
    sock.write("GET " + path + " HTTP/1.1\r\n");
    sock.write("Host: " + host + "\r\n");
    sock.write("Connection: close\r\n");
    sock.write("\r\n");
    sock.shutdown(SHUT_WR);

    while (!sock.eof()) {
        cout << sock.read();
    }
    sock.close();

    cerr << "Function called: get_URL(" << host << ", " << path << ").\n";
    // cerr << "Warning: get_URL() has not been implemented yet.\n";
}

测试结果,如下:

image-20230707012244859

image-20230707012218262

ByteStream

要求实现一个运行在内存的有序可靠字节流(An in-memory reliable byte stream),类似于管道。要求如下:

  • 字节流可以从写入端写入,并以相同的顺序,从读取端读取
  • 字节流是有限的,写者可以终止写入。而读者可以在读取到字节流末尾时,产生 EOF标志,不再读取
  • 所实现的字节流必须支持流量控制,以控制内存的使用。当所使用的缓冲区爆满时,超过缓冲区容量的内容直接丢弃。字节流会返回成功写入的字节数
  • 写入的字节流可能会很长,必须考虑到字节流大于缓冲区大小的情况。即便缓冲区只有1字节大小,所实现的程序也必须支持正常的写入读取操作

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

网上很多博客是采用 std::deque<char> 实现的,用它实现很好想也容易写,但是 std::deque<char> 的底层实现并不是连续的数组,会带来额外的开销,而现在的需求是容量(capacity)是在初始化后就确定的,因此我采用 std::vector<char> 来实现。

为了能够放入 capacity bytes,我们需要开辟 capacity + 1 的空间。否则就无法区分全空和全满状态。

声明部分代码如下:

//! \brief 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::vector<char> _buffer;  //!< The buffer of the stream
    size_t _capacity;         //!< The capacity of the stream
    size_t _written_cnt;  //!< The number of bytes written
    size_t _read_cnt;     //!< The number of bytes read
    int _head, _tail;     //!< The head and tail of the buffer
    bool _input_ended_flag = false;  //!< Flag indicating that the input has ended
    bool _error = false;  //!< Flag indicating that the stream suffered an error.

  public:
    //! Construct a stream with room for `capacity` bytes.
    ByteStream(const size_t capacity);

    //! \name "Input" interface for the writer
    //!@{

    //! Write a string of bytes into the stream. Write as many
    //! as will fit, and return how many were written.
    //! \returns the number of bytes accepted into the stream
    size_t write(const std::string &data);

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

    //! \name "Output" interface for the reader
    //!@{

    //! Peek at next "len" bytes of the stream
    //! \returns a string
    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
    //! \returns a string
    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;
    //!@}

    //! \name General accounting
    //!@{

    //! Total number of bytes written
    size_t bytes_written() const;

    //! Total number of bytes popped
    size_t bytes_read() const;
    //!@}
};

成员函数实现代码如下:

ByteStream::ByteStream(const size_t capacity) : _buffer(capacity + 1), _capacity(capacity), _written_cnt(0),
                                                _read_cnt(0), _head(0), _tail(_capacity) {}

size_t ByteStream::write(const string &data) {
    auto ret = min(data.size(), remaining_capacity());
    for (size_t i = 0; i < ret; ++i) {
        _tail = (_tail + 1) % (_capacity + 1);
        _buffer[_tail] = data[i];
    }
    _written_cnt += ret;
    return ret;
}

//! \param[in] len bytes will be copied from the output side of the buffer
string ByteStream::peek_output(const size_t len) const {
    string ret;
    auto n = min(len, buffer_size());
    for (size_t i = 0; i < n; ++i) {
        ret.push_back(_buffer[(_head + i) % (_capacity + 1)]);
    }
    return ret;
}

//! \param[in] len bytes will be removed from the output side of the buffer
void ByteStream::pop_output(const size_t len) {
    auto n = min(len, buffer_size());
    _head = (_head + n) % (_capacity + 1);
    _read_cnt += n;
}

//! 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
string ByteStream::read(const size_t len) {
    auto ret = peek_output(len);
    pop_output(len);
    return ret;
}

void ByteStream::end_input() { _input_ended_flag = true; }

bool ByteStream::input_ended() const { return _input_ended_flag; }

size_t ByteStream::buffer_size() const { return (_tail - _head + 1 + _capacity + 1) % (_capacity + 1) ; }

bool ByteStream::buffer_empty() const { return buffer_size() == 0; }

bool ByteStream::eof() const { return _input_ended_flag && buffer_empty(); }

size_t ByteStream::bytes_written() const { return _written_cnt; }

size_t ByteStream::bytes_read() const { return _read_cnt; }

size_t ByteStream::remaining_capacity() const { return _capacity - buffer_size(); }

测试

image-20230708114305457

References

我使用的 Sponge 仓库

CS144 计算机网络 Lab0

康宇PL’s Blog-【计算机网络】Stanford CS144 Lab Assignments 学习笔记

评论

  1. last-whisper
    Macintosh Chrome 115.0.0.0
    2月前
    2023-8-13 19:44:56

    hey 哥们我发现 github 上官方换了 minnow 后我的环境就死活搭不起来。你现在用的 lab 的 pdf 是哪个版本的呀~ 最新的版本的环境配不动。

    • 博主
      last-whisper
      Windows Chrome 115.0.0.0
      2月前
      2023-8-13 19:52:43

      PDF 我用的 Fall 2021 的版本,实验框架还是旧的 Sponge,新的 Minnow 网上教程几乎没有,当然写经典旧版学习更方便🙂

      • last-whisper
        admin52
        Macintosh Chrome 115.0.0.0
        2月前
        2023-8-13 19:55:16

        你好~ 请问 Fall 2021 的版本请问还有嘛?我今天下午搭了一个下午 2023 Spring 的环境都 fail 了,人麻了 TAT。可以一起交流下嘛,mail: pkuwkl@gmail.com (☆ω☆),如果可以的话我们在上面交流吧~

        • 博主
          last-whisper
          Windows Chrome 115.0.0.0
          2月前
          2023-8-13 19:58:17

          可以呀,加 qq 525687841 聊吧

  2. yoo2i
    Windows Edge 116.0.1938.62
    1月前
    2023-8-31 19:45:12

    老哥,搭环境搭麻了,方便加你qq请教一下吗

    • 博主
      yoo2i
      Windows Chrome 115.0.0.0
      1月前
      2023-8-31 22:35:56

      可以的

  3. eightclounde
    Windows Edge 116.0.1938.76
    3周前
    2023-9-12 19:28:33

    老哥 拉的你的仓库 回退到你的仓库 写好lab0的webget make check_webget 然后 testing webget 直接就跳出来Build target check_webget 没有看到样例测试 拉了好几遍都是这样 用的ubuntu20.04 这是为什么啊 /(ㄒoㄒ)/

    • 博主
      eightclounde
      Windows Chrome 115.0.0.0
      3周前
      2023-9-12 19:46:53

      先 make 编译再 make check_webget 吧,webget 就只有 1 个测试用例吧

      • eightclounde
        admin52
        Windows Edge 116.0.1938.76
        3周前
        2023-9-12 23:03:56

        对啊 就是这样的 但是 tests pass 跟时间那些都没跳出来 然后就直接build target了 只跳出来两行 一行testing webget 然后下一行就是Build target check_webget了 = =

        • 博主
          eightclounde
          Windows Chrome 116.0.0.0
          3周前
          2023-9-13 19:27:40

          没看懂,我也没遇到过🌝

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇