CS144-check0

本文最后更新于:2024年3月23日 下午

因为一些个人安排的原因,决定先学一下network再回头写6.1810,于是开始了这个非常棒的Stanford的lab。课程官网在https://cs144.github.io/ , 会随着时间更新,如果本学期课结束了的话我考虑把实验要求的pdf放上来。

似乎这个课今年加了很多东西,尤其是C++23的新特性,所以学起来很新鲜。当然,笔者的水平完全达不到Modern C++的要求,所以很多代码肯定会有疏漏。

实验环境为WSL Debian + gcc13.1,前面的部分略过,从代码开始

语法

这里出现了一些很新的cpp语法特性(起码对我来说很新), string_view 和 static_cast

C++17中我们可以使用std::string_view来获取一个字符串的视图,类似于Golang的slice。字符串视图并不真正的创建或者拷贝字符串,而只是拥有一个字符串的查看功能。显然大部分的字符串操作不需要真正拥有这个字符串,所以这个C++风格的string ref可以便捷地提高性能。参阅

可以看到在下文webget的调用中通过span返回了一个对参数的view。

static_cast是一个C++风格的类型转换,与其他类型转换的区别参阅什么时候应该使用static_cast、dynamic_cast、const_cast和reinterpret_cast?

Webget

其实是一个源码阅读练习,所以才说We expect you’ll need to write about ten lines of code.(笑

我们发现Address类的构造函数长这样

1
Address( const std::string& hostname, const std::string& service );

发现TCPSocket继承了父类Socket的connect方法,之后进行系统调用来解析地址

1
void connect( const Address& address );

事实上socket是fd的子类,但现在不重要、

所以我们的webget就很自然的写好了

似乎这里需要一些科学上网(?,我的网络配置是wsl的mirrored mode和clash for win的TUN mode。接管了所有对外的网络请求。

1
2
3
4
5
6
7
8
9
10
11
12
13
void get_URL( const string& host, const string& path )
{
Address addr(host,"http");
TCPSocket sock;
sock.connect(addr);
string req = "GET " + path + " HTTP/1.1\r\nHost: " + host + "\r\n" + "Connection: close\r\n\r\n";
sock.write(req);
string buf;
while (!sock.eof()){
sock.read(buf);
cout << buf;
}
}

An in-memory reliable byte stream

要求类似于写一个pipe,然后输入输出。不需要考虑并发。

缓冲区使用vector或者string都是无所谓的,只要维护好size和capacity就可以。

首先在父类添加需要的protected成员变量(注释已经告诉你怎么加了qwq

1
2
3
4
5
6
7
8
9
10
class ByteStream
{
protected:
// Please add any additional state to the ByteStream here, and not to the Writer and Reader interfaces.
···
bool is_closed_ {};
std::string buffer_ {};
uint64_t bytes_pushed_ {};
uint64_t bytes_popped_ {};
};

之后就把每个要求实现的都实现就好了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
ByteStream::ByteStream( uint64_t capacity ) : capacity_( capacity ) { 
buffer_.reserve( capacity );
}

bool Writer::is_closed() const
{
return this->is_closed_;
}

void Writer::push( string data )
{
size_t available_capacity = this->available_capacity();
size_t bytes_to_copy = min(data.size(), available_capacity);

buffer_ += data.substr(0, bytes_to_copy);
bytes_pushed_ += bytes_to_copy;
}

void Writer::close()
{
is_closed_ = true;
}

uint64_t Writer::available_capacity() const
{
return capacity_ - buffer_.size();
}

uint64_t Writer::bytes_pushed() const
{
return bytes_pushed_;
}

bool Reader::is_finished() const
{
return ((is_closed_ == true) && (this->bytes_buffered() == 0));
}

uint64_t Reader::bytes_popped() const
{
return bytes_popped_;
}

string_view Reader::peek() const
{
string_view sv( buffer_.data() , min(static_cast<uint64_t>(1000),this->bytes_buffered()));
return sv;
}

void Reader::pop( uint64_t len )
{
buffer_.erase( buffer_.begin() , buffer_.begin() + len );
bytes_popped_ += len;
}

uint64_t Reader::bytes_buffered() const
{
return buffer_.size();
}

因为我们在构造函数中处理好了string的capacity,所以在push的过程中就不需要考虑了。

这里卡我的点是peek,因为我当时望文生义了

1
std::string_view peek() const; // Peek at the next bytes in the buffer

所以我的peek一开始真的只返回了next byte(
后来speedtest过不了,只能跑0.03gbps。看到了read函数的实现,于是修改成了上面的样子,就好了。


CS144-check0
http://tzr.icu/20240305/CS144-check0/
发布于
2024年3月5日
更新于
2024年3月23日
许可协议