Skip to content

Lab Checkpoint 0: networking warmup

Lab 0 代码在 master 分支上

2. Networking by hand

telnet cs144.keithw.org http

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

image.png

image.png

心累…… 一开始一直获取不到,以为是网络的问题,然后自己搭建了一个 http 服务,结果还是不行。 然后再读了一遍文档,发现最后要输入一个空行…… 读文档要仔细啊!

3. Writing a network program using an OS stream socket

Commands

make

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

make check_webget

通过查看文档中 TCPSocket Class 的用法,可以写出下面的代码。

void get_URL(const string &host, const string &path) {
    TCPSocket socket;
    socket.connect(Address(host, "http"));

    socket.write("GET " + path + " HTTP/1.1\r\n");
    socket.write("Host: " + host + "\r\n");
    socket.write("Connection: close\r\n");
    socket.write("\r\n");

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

    socket.close();

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

image.png

image.png

4. An in-memory reliable byte stream

Commands

make

make check_lab0
要求实现可靠的字节序列,能保证顺序写入读取,考虑使用 deque 来实现,因为方便实现 peek 操作(读取前 n 个字符)。按照代码注释和文档实现功能即可,难度不大。代码如下:

byte_stream.hh

#include <string>
#include <deque>

class ByteStream {
  private:
    std::deque<char> _myqueue;
    size_t _capacity;
    bool _input_ended;
    size_t _bytes_written;
    size_t _bytes_read;
    bool _error{};  //!< Flag indicating that the stream suffered an error.

  public:
    // some codes...
}

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): _myqueue({}), _capacity(capacity), _input_ended(false), _bytes_written(0), _bytes_read(0) { }

size_t ByteStream::write(const string &data) {
    const size_t len = data.length();
    size_t res = 0;
    for (size_t i = 0; i < len; i++) {
        if (_myqueue.size() < _capacity) {
            _myqueue.push_back(data[i]);
            res++;
            _bytes_written++;
        }
        else {
            break;
        }
    }
    return res;
}

//! \param[in] len bytes will be copied from the output side of the buffer
string ByteStream::peek_output(const size_t len) const {
    string res;
    size_t realPeekLen = len;
    if (_myqueue.size() < realPeekLen) {
        realPeekLen = _myqueue.size();
    }
    res.assign(_myqueue.begin(), _myqueue.begin() + realPeekLen);

    return res;
}

//! \param[in] len bytes will be removed from the output side of the buffer
void ByteStream::pop_output(const size_t len) {
    size_t realPopLen = len;
    if (_myqueue.size() < realPopLen) {
        realPopLen = _myqueue.size();
    }
    _bytes_read += realPopLen;
    for (size_t i = 0; i < realPopLen; i++) {
        _myqueue.pop_front();
    }
}

//! 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 res = peek_output(len);
    pop_output(len);

    return res;
}

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

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

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

bool ByteStream::buffer_empty() const { return _myqueue.size() == 0; }

bool ByteStream::eof() const {
    if (_input_ended && _myqueue.size() == 0) {
        return true;
    }
    else {
        return false;
    }
}

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 - _myqueue.size(); }

image.png