天天看点

Stanford CS144: Lab 0

遵循一些代码的守则:

  • 不用 malloc() free() new delete
  • 不用空指针和智能指针
  • 不用模板,线程,锁,虚函数
  • 不用c风格的字符串,直接用cpp的string
  • 不要使用c风格的强制转换,使用cpp的 static_cast(在cs144中不太会用到)
  • 最好使用常量引用去传递函数的参数
  • 不会改变的变量设为常量
  • 不会改变内容的函数,设为const函数
  • 避免使用全局变量,尽量使得每个变量的作用域最小
  • 提交之前,通过 **make format ** 去检查代码风格。

Part 1

Lab 0非常简单,就是模仿telnet,向server发请求,然后把返回的信息打印出来。

主要这边就是先熟悉一下 FileDescriptor、Socket、Address三个类,当然不熟悉也可以直接仿照 socket_example_2.cc去实现。

其中没有看懂 Socket 和 Address 是怎么联系起来的,而且它里面很多都是系统调用。

直接贴代码

void get_URL(const string &host, const string &path) {
    TCPSocket sock1;
    sock1.connect(Address(host, "http"));
    string request = "GET "+ path + " HTTP/1.1\r\nHost: " + host + "\r\nConnection: close\r\n\r\n";
    string str;
    sock1.write(request);

    while(!sock1.eof()){
        cout<<sock1.read();
    }
    sock1.close();			// 记得关闭socket,不然检测会b
}
           

Part 2

第二部分是写一个在内存中的可信赖字节流。就是类似于buffer的东西,提供了接口形式去实现就行了。总体上不难,但是需要去理解给的接口的作用,这个是在调试的时候可以比较好的理解。

我这边实现的主体思路就是循环队列。

直接贴代码了,然后说几点遇到的问题。

  • num_of_read是取决于 pop_output 而不是 read
  • end_input_flag 需要主动调用函数end_input() 去修改,而不是在write 未写完的情况下去修改
// part of byte_stream.hh
// 主要就是增加了几个成员
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::string buf{};
    size_t start{},end{},cap{};
    size_t num_of_write{},num_of_read{};

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

using namespace std;

ByteStream::ByteStream(const size_t capacity) {
    cap = capacity + 1;
    buf.resize(capacity + 1);
    start = 0;
    // the case that (end + 1) mod cap == start represents there is no info in buf
    end = capacity;
    num_of_write = num_of_read = 0;
    end_input_flag = false;
    _error = false;
}

size_t ByteStream::write(const string &data) {
    size_t ret = 0;
    ret = min(remaining_capacity(),data.size());
    for(int i = 0,limit = static_cast<int>(ret);i < limit;i++){
        end = (end + 1) % cap;
        buf[end] = data[i];
    }
    // if write is not end,modify the flag
    num_of_write += ret;
    end_input_flag = false;

    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;
    ret.resize(len);
    for(int i = 0,limit = static_cast<int> (len);i < limit;i++){
        ret[i] = buf[(start + i) % cap];
    }
    return ret;
}

//! \param[in] len bytes will be removed from the output side of the buffer
void ByteStream::pop_output(const size_t len) {
    start = (start + len) % cap;
    num_of_read += len;
}

//! 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) {
    size_t sz = min(buffer_size(),len);
    printf("sz : %d\n",static_cast<int> (sz));
    string ret = peek_output(sz);
    pop_output(sz);
    return ret;
}

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

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

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

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

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

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

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

size_t ByteStream::remaining_capacity() const {
    size_t e = end,s = start;
    if((e + 1)%cap == s)
        return cap - 1;
    if(s <= e)
        s += cap;
    return s - e - 2;
}

           

不知道为啥 make format用不了~

还有就是不知道为啥有时候 test 6会失败

Stanford CS144: Lab 0
LAB

继续阅读