CS144 Lab0: 热身

最近秋招太难了,已经没几个面试了,目前只有byd一个保底的offer。论文送审还没出结果。
最近面试问网络问的还挺多的,闲的没事在这里开一个新坑吧,cs144,实现网络协议栈相关的东西。

1. 体验网络的使用

1.1 获取网页

  1. 访问 http://cs144.keithw.org/hello 可以看到 Hello, CS144! 字样
  2. 使用 telnet 体验http交互
telnet cs144.keithw.org http
GET /hello HTTP/1.1
Host: cs144.keithw.org
Connection: close

结果和上面一样
在这里插入图片描述
3. 使用同样方法访问 http://cs144.keithw.org/lab0/, sunetid是一个任意id,输入的和上面类似

telnet cs144.keithw.org http
GET /lab0/123 HTTP/1.1
Host: cs144.keithw.org
Connection: close

在这里插入图片描述
响应头中包含的X-Your-Code-Is 为 729256

1.2 发送邮件

这部分也是用telnet体验下smtp协议,没有stanford邮箱,也懒得用其他邮箱了,直接跳过

1.3 使用netcat进行监听和连接

这部分就是用 netcat -v -l -p 9000监听并用 telnet localhost 9000进行连接,比较简单,跳过

2. 编写webget获取http数据

只需要用TcpSocket和Address类即可,创建Socket并连接到访问的地址,并发送HTTP数据,然后从socket读取数据并打印即可。

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 s;
    s.set_reuseaddr();
    Address addr(host, "http");

    s.connect(addr);

    string data = "GET " + path + " HTTP/1.1\r\n" +
                "HOST: " + host + "\r\n" +
                "Connection: close\r\n" +
                "\r\n";
    s.write(data);

    while (true) {
        auto datagram = s.read();
        if (!datagram.length()) {
            break;
        } else {
            cout << datagram;
        }
    }
}

3. 编写字节流类

字节流类是用于通信的一个类,保存了一些字节流的数据。其具有最大容量,写满了就不能再写,等待数据被读取一部分才能继续写入。
这部分不难,我新增的成员如下:

   std::string buf_;	// 环形缓冲区
   size_t read_idx_;	// 累计读取的字节数
   size_t write_idx_;	// 累计写入的字节数
   size_t capacity_;	// 缓冲区大小上限
   bool input_ended_;	// 后续是否不再写入

定义好成员后,后面的相关函数实现就比较简单了,如下:

static size_t rounddown(size_t size, size_t factor) {
    return size - size % factor;
}

ByteStream::ByteStream(const size_t capacity): 
    buf_(), read_idx_(0), write_idx_(0), capacity_(capacity), input_ended_(false) 
    {}

size_t ByteStream::write(const string &data) {
    if (input_ended_) {
        return 0;
    }

	// 这里让buf的实际大小随需要增长,也可以直接初始化为capacity_大小
    if (buf_.length() < capacity_ && write_idx_ + data.length() >= buf_.length()) {
        buf_ = buf_  + string(min(max(buf_.length(), data.length()), capacity_ - buf_.length()), ' ');
    }

	// 计算实际能写入的字节数,并且因为是环形的,如果跨越了缓冲区的首尾,那么需要分成两段,分别使用memcpy复制字节
    size_t write_size = min(remaining_capacity(), data.length());
    size_t roundup_size = rounddown(write_idx_ + capacity_, capacity_);
    size_t seg1_size = min(roundup_size, write_idx_ + write_size) - write_idx_;

    memcpy(getidx(write_idx_), data.c_str(), seg1_size);
    memcpy(getidx(0), data.c_str() + seg1_size, write_size - seg1_size);
    
    write_idx_ += write_size;
    return write_size;
}

//! \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 read_size = min(len, buffer_size());
    if (!read_size)  {;
        return "";
    }

    string ans;
    size_t roundup_size = rounddown(read_idx_ + capacity_, capacity_);
    size_t seg1_size = min(roundup_size, read_idx_ + read_size) - read_idx_;

    ans += buf_.substr(read_idx_ % capacity_, seg1_size);
    ans += buf_.substr(0, read_size - seg1_size);
    return ans;    
}

//! \param[in] len bytes will be removed from the output side of the buffer
void ByteStream::pop_output(const size_t len) {
    read_idx_ += min(len, buffer_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) {
    auto ans = peek_output(len);
    pop_output(ans.length());
    return ans;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值