Checkpoint0: networking warmup


Networking by hand

在Web browser中访问网页

接下来用命令手动完成浏览器所做的操作。

tinuvile@LAPTOP-7PVP3HH3:~$ telnet cs144.keithw.org http
Trying 104.196.238.229...
Connected to cs144.keithw.org.
Escape character is '^]'.
^]
telnet> close
Connection closed.

这个命令指示telnet程序在我的电脑和cs144.keithw.org电脑间建立一个字节流连接,并访问该电脑上运行的特定服务http

然后GET会告知服务器URL路径,Host输入主机部分,close以及句末回车再回车告知服务器已经完成HTTP请求。完整的如下:

tinuvile@LAPTOP-7PVP3HH3:~$ telnet cs144.keithw.org http
Trying 104.196.238.229...
Connected to cs144.keithw.org.
Escape character is '^]'.
GET /hello HTTP/1.1
Host: cs144.keithw.org
Connection: close

HTTP/1.1 200 OK
Date: Tue, 22 Apr 2025 10:04:29 GMT
Server: Apache
Last-Modified: Thu, 13 Dec 2018 15:45:29 GMT
ETag: "e-57ce93446cb64"
Accept-Ranges: bytes
Content-Length: 14
Connection: close
Content-Type: text/plain

Hello, CS144!
Connection closed by foreign host.

Listening and connecting

这个是作为一个简单服务器的角色。在一个终端窗口中输入:

然后在另一个终端中输入:

这时候第一个终端窗口会出现:

表明已经连接成功了。netcat是服务器端,telnet是客户端。

然后在netcat窗口ctrl+C退出程序,telnet也会立即退出。


Writing a network program using an OS stream socket

这个实验要用到Linux内核提供的stream socket功能,这个功能可以在两台计算机间创建可靠的双向字节流。

实验设计基于Unix套接字API,所以需要在Linux或者WSL环境下完成。我用的是Ubuntu 20.04.6 LTS

编译源代码。

课程给我们提供了一些编码建议,希望充分利用新特性实现最大程度的安全编程,可查阅C++ Core Guidelines。核心理念是确保每个对象的设计具备尽可能小的公开接口,包含大量内部安全检查机制,难以被误用,并能自主清理资源。具体来说:

  • 避免成对操作,如malloc/free,new/delete,因为这些操作的后者可能因为函数提前返回或抛出异常而无法执行。建议采用Resource acquisition is initialization的模式(RAII),操作应在对象构造函数中完成,逆向操作则应在析构函数中自动执行。

  • 尽量不要使用原始指针,必要时使用智能指针unique_ptrshared_ptr

  • 避免使用模板、线程、锁和虚函数。

  • 避免使用C风格字符串char *str或字符串函数,改用std::string

  • 切勿使用C风格类型转换,必要时使用C++的static_cast

  • 函数参数传递优先使用常量引用方式,如const Address & address

  • 所有不需要修改的变量和方法都声明为const

  • 避免使用全局变量,尽可能为每个变量赋予最小的作用域。

  • 提交作业前运行cmake --build build --target tidy获取改进建议,并运行cmake --build build --target format保持代码格式一致。

Reading the Minnow support code

公共接口部分阅读util/socket.hhutil/file_descriptor.hh。继承关系为TCPSocketSocketFileDescriptor,关键部分列在下面:

file_descriptor.hh

这个类是一个引用计数的文件描述符句柄,用shared_ptr管理FDWrapperFDWrapper封装了底层的文件描述符。然后这个类将 POSIX 系统调用封装成了 C++ 方法。

socket.hh

Socket继承自FileDescriptor,增加了网络相关的方法,子类TCPSocketUDPSocket进一步特化。

Writing webget

HTTP 请求是通过 TCP 连接发送的纯文本字节流,write方法将字节流写入文件描述符。

运行测试:

运行cmake --build build --target check_webget通过。


An in-memory reliable byte stream

这个任务需要我们实现字节流功能。这个字节流是有限容量的,写入的数据不能超过当前可用容量。当写入者写入数据时,如果缓冲区已满,只能写入部分数据。读取者可以读取数据,并从缓冲区中移除已读取的部分,这样释放空间,让写入者可以继续写入。同时,写入者可以关闭流,读取者在读取完所有数据后会到达EOF。

首先ByteStream需要维护一个缓冲区,我选用的是std::string

然后实现ReaderWriter的具体函数,比较简单。

运行测试。

提交前用clang-format统一代码风格。

这样就算完成了。

Last updated