cs144是计算机网络中一个比较硬核的项目,十分利于学习现代c++和软件架构的初步理解
现在最新是Stanford Minnow版本使用了c++ 20的标准
两者都可以选择去做,但更推荐Minnow版本,它更新,并且会涉及一些更高级的语法
两个版本差别不大,但是结构会有不同
注意事项
这个项目需要对现代c++的语法有一定基础才能上手,虽然项目整体代码量不算大,
但是要理解整个项目设计,还是需要一些难度和时间
一定要自己去阅读实验文档,Minnow的文档要比Sponge的文档更加言简意赅,清晰明了,推荐阅读Minnow文档
前置知识
-
虚拟机
这个没什么好说的,自己去配置一个网络开发环境,配置一个符合你习惯的环境
-
现代c++语法
至少需要了解c++ 11标准的语法
-
基本的git使用
无论是Minnow还是Sponge都是采用将每一个Lab的startercode放在分支中,需要合并。不仅如此,git版本控制将贯穿整个学习流程
-
Make/make
这个仅会使用即可,一般不需要修改相关配置
如果你是第一次接触c++项目,头痛是正常的,在现代的c++中都充斥着各种新语法,
不仅如此在封装中还充斥着一些容易忽视的语法细节,但现在有LLM,能够很好地帮助我们了解这些特性
建议
首先选择上面我贴出来的两个仓库地址中的一个,将他fork下来,自己回滚
这样有利于我们进行代码管理
Lab0 start
Webget
这个是一个开始,利用Linux内核中实现好的tcp协议进行网络通信
根据文档编写apps/webget.cc
void get_URL( const string& host, const string& path )
{
TCPSocket socket {};
socket.connect( Address( host, "http" ) );
string data_send = "GET " + path + " HTTP/1.1\r\nHost: " + host + "\r\n" + "Connection: close\r\n\r\n";
socket.write( data_send );
while ( !socket.eof() ) {
string result;
socket.read( result );
cout << result;
}
socket.close();
// cerr << "Function called: get_URL(" << host << ", " << path << ")\n";
// cerr << "Warning: get_URL() has not been implemented yet.\n";
}
ByteStream
它是处理网络IO的最底层,接下来的Lab都要在ByteStream的实现之上
所以一定要注意程序运行时间
它的本质是实现一个FIFO的数据结构,直觉来讲会用到队列
但是这里的实现没有那么复杂,仅仅需要std::string即可
class ByteStream
{
public:
explicit ByteStream( uint64_t capacity );
// Helper functions (provided) to access the ByteStream's Reader and Writer interfaces
Reader& reader();
const Reader& reader() const;
Writer& writer();
const Writer& writer() const;
void set_error() { error_ = true; }; // Signal that the stream suffered an error.
bool has_error() const { return error_; }; // Has the stream had an error?
protected:
// Please add any additional state to the ByteStream here, and not to the Writer and Reader interfaces.
uint64_t capacity_;
bool error_ {};
std::string buffer_ {};
size_t total_push_ {};
size_t total_pop_ {};
bool closed {};
};
void Writer::push( string data )
{
// 计算写入字节数
size_t writing_size = std::min( data.size(), available_capacity() );
buffer_ += data.substr( 0, writing_size );
total_push_ += writing_size;
}
void Writer::close()
{
// Your code here.
closed = true;
}
bool Writer::is_closed() const
{
return closed;
}
uint64_t Writer::available_capacity() const
{
return capacity_ - buffer_.size();
}
uint64_t Writer::bytes_pushed() const
{
return total_push_;
}
string_view Reader::peek() const
{
return string_view( buffer_.data(), buffer_.size() );
}
void Reader::pop( uint64_t len )
{
buffer_ = buffer_.substr( len );
total_pop_ += len;
}
bool Reader::is_finished() const
{
return closed && buffer_.empty();
}
uint64_t Reader::bytes_buffered() const
{
return buffer_.size();
}
uint64_t Reader::bytes_popped() const
{
return total_pop_;
}
这样即可实现
测试
mkdir build && cd build
cmake .. && make && make check0
这样即可进行测试