[CS144] Lab 0: networking warmup

Lab 0: networking warmup

1 Set up GNU/Linux

参考链接: BYO Linux installation
额外安装的包: clang-tidy-6, clang-format-6.0, libpcap-dev,mininet, wireshark-qt, doxygen, graphviz, cppcheck

  • 若安装的为 clang-format-7, 直接安装后执行 cmake .. 后运行 make format 会显示找不到 clang-format. 根据 clang_format.cmake 中的代码, 需要添加环境变量 CLANG_FORMAT.
    在这里插入图片描述
    直接安装 clang-format-6.0, 则无需配置环境变量.
  • clang-tidy 同样有上述问题, 根据 clang_tidy.cmake 中的代码, 必须设置 CLANG_TIDY 环境变量
    在这里插入图片描述

2 Networking by hand

2.1 Fetch a Web page

在终端输入以下指令:

$ telnet cs144.keithw.org http
GET /hello HTTP/1.1
Host: cs144.keithw.org
Connection: close

在这里插入图片描述

  • 注: 在输入完上述内容后需要再按一次回车.

2.2 Send yourself an email

此处由于没有斯坦福大学的邮箱账号, 故选用 QQ 的 SMTP 服务, 其配置具体可参考: 利用Telnet登录qq邮箱发送邮件——SMTP协议学习_Fossette_lhx的博客-CSDN博客
输入过程截图如下:

DATA 中输入 . 表示结束后, 邮件就会被发送:
在这里插入图片描述

  • 注: 与实验指导中的邮箱格式不同, QQ 在 SMTP 中输入的邮箱地址都必须由 <> 括起.

2.3 Listening and connecting

一个终端作为服务端, 输入以下指令(注意与实验指导不同, 需要额外添加参数 -n):

$ netcat -v -l -n -p 9090

另一个终端作为客户端, 输入一下命令来连接服务端:

$ telnet localhost 9090

在这里插入图片描述

3 Writing a network program using an OS stream socket

3.4 Writing webget

思路

实现 apps/webget.cc 中的 get_URL().
实现思路基本按照实验指导的提示和代码注释, 建立连接后发送 HTTP 请求报文. 然后打印回复报文的内容. 由于回复报文可能不止一个, 因此需要通过检查 EOF 标志位来判断是否接收完毕.

代码

apps/webget.cc

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).

    const Address addr(host, "http");
    TCPSocket tcpSocket;
    tcpSocket.connect(addr);  // connect the HTTP server

    // construct the HTTP header and send to the server
    string httpHeader;
    httpHeader.append("GET ").append(path).append(" HTTP/1.1\r\n")
        .append("Host: ").append(host).append("\r\n")
        .append("Connection: close\r\n")
        .append("\r\n");
    if (tcpSocket.write(httpHeader) != httpHeader.size()) {
        cerr << "HTTP request failed.\n";
        return;
    }

    // read and print the output from the server until reaching “EOF”
    while (!tcpSocket.eof()) {
        cout << tcpSocket.read();
    }
    tcpSocket.close();  // close the TCP connection

    //    cerr << "Function called: get_URL(" << host << ", " << path << ").\n";
    //    cerr << "Warning: get_URL() has not been implemented yet.\n";
}
测试
  • build 目录下执行 make 后, 运行 webget, 成功得到 HTTP 报文:
    在这里插入图片描述
  • build 目录下执行 make check_webget:
    在这里插入图片描述

4 An in-memory reliable byte stream

思路

该部分是实现一个内存中可靠字节流的缓冲区数据结构. 根据实验指导的描述, 该数据结构有一个数据写入者和一个数据读取者, 是一个典型的队列模型. 而考虑到其需要实现的接口中写入和读出的可以是一段字节流, 且有只读不取的 peek_output() 方法, 因此自己实现基于循环队列的缓冲区是比较麻烦的, 因此考虑使用 STL 中的模板, 但由于 queue 队首不能多元素只读不取, 因此可以想到使用双端队列模板 deque.
此外, 由于是基于字节的, 因此容易想到直接使用 string, 虽然 string 的实现类似于 vector, 但在此处和 deque 的差别不大, 且在 Lab4 中证实性能要优于 deque.
整体上, 目前代码能够完成测试, 但考虑到实验指导在一些地方说明的不是很详尽, 后续仍可能需要改动.

代码

libsponge/byte_stream.hh
#ifndef SPONGE_LIBSPONGE_BYTE_STREAM_HH
#define SPONGE_LIBSPONGE_BYTE_STREAM_HH

#include <string>

//! \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.
    const size_t _cap;   //! The capacity of the stream buffer

    std::string _buffer{};   //!< Byte stream buffer
    size_t _total_read = 0;     //!< Total number of bytes written
    size_t _total_written = 0;  //!< Total number of bytes popped
    bool _end = false;      //!< Flag indicating that the byte stream has reached its ending.
    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;
    //!@}
};

#endif  // SPONGE_LIBSPONGE_BYTE_STREAM_HH
libsponge/byte_stream.cc
#include "byte_stream.hh"

// 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`

template <typename... Targs>
void DUMMY_CODE(Targs &&.../* unused */) {}

using namespace std;

ByteStream::ByteStream(const size_t capacity) : _cap(capacity), _buffer() {}

size_t ByteStream::write(const string &data) {
    const size_t size = min(data.size(), _cap - _buffer.size());
    _buffer.append(data, 0, size);
    _total_written += size;
    return size;
}

//! \param[in] len bytes will be copied from the output side of the buffer
string ByteStream::peek_output(const size_t len) const {
    return {_buffer, 0,min(len, _buffer.size())};
}

//! \param[in] len bytes will be removed from the output side of the buffer
void ByteStream::pop_output(const size_t len) {
    const size_t size = min(len, _buffer.size());
    _buffer.erase(0, size);
    _total_read += size;
}

//! 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) {
    const size_t size = min(len, _buffer.size());
    string str = _buffer.substr(0, size);
    _buffer.erase(0, size);
    _total_read += size;
    return str;
}

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

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

size_t ByteStream::buffer_size() const { return _buffer.size(); }

bool ByteStream::buffer_empty() const { return _buffer.empty(); }

bool ByteStream::eof() const { return _end && _buffer.empty(); }

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

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

size_t ByteStream::remaining_capacity() const { return _cap - _buffer.size(); }

测试

build 目录下执行 make 后执行 make check_lab0:
在这里插入图片描述

  • 注: 其中 t_webget 和 t_address_dt 两项耗时较长的原因在于二者需要分别访问 cs144.keithw.org 和谷歌官网两个外网, 所以耗时较长.
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值