CS144 Lab0

2026-01-21

cs144是计算机网络中一个比较硬核的项目,十分利于学习现代c++和软件架构的初步理解

现在最新是Stanford Minnow版本使用了c++ 20的标准

Sponge版本

Minnow版本

我的实现

两者都可以选择去做,但更推荐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

这样即可进行测试