Standford CS144 Lab 0
序言
满怀热忱开始 cs144 的旅途,第一个碰到的困难便是环境搭建。在这三天时间里不断配置、删库、配置,看了不知道多少博客(许多都是跟着文档一笔带过)和评论,最后终于完成了实验环境的搭建!
最初是打算做 SU CS144 最新的 2024 Spring minnow
版本,但是它要求需要 ubuntu23、gcc 和 g++13 以上,如果环境没有达到实验要求,后面的 cmake 会出错。因此最后还是 2021 的Sponge
版(听说这个版本的 lab4 TCP Connection 特别难,而在 minnow 版中直接换成了另一个简单的 lab)。
环境配置
我选择的是WSL2+VScode的方式进行实验,WSL2 安装起来非常简便而且体量轻,不仅可以在基于 Linux 的环境中进行开发,使用特定于 Linux 的工具链和实用程序,还可以在 Windows 上舒适地运行和调试基于 Linux 的应用程序。
工具链:gcc &g++ 13.1.0、gdb 12.1、make(由于我对于 gcc、g编译器,还有cmake
、make
、gdb
都不了解,甚至 C也是现学现用的,因此配置过程中遇到了非常多的问题,耗费了大量时间和精力)
环境搭建
1. 从官网下载解压 gcc 和 g++
2. 拉取 start code
–获取项目框架
由于 Stanford 官方已经把Sponge
的代码库换成了最新的Minnow
的库,所以为了拉到开始代码得去拉别人已经做好的实验,再用 git 回退到初始状态。非常感谢老哥 LRL52 提供的Lab start code
–git 关联远端仓库
- 由于 start code 是从别人的代码仓库上 clone 到本地的,如果此时直接关联自己的远程仓库
git remote add origin <URL>
,则会报错error: remote origin already exists
- 解决方法: 1.
git remote rm origin
删除关联的远程库 2.git remote add origin <URL>
关联自己的远程库 3.git push origin main
把本地仓库推送到远程仓库(Github 配置 SSH)
3. 根据官方文档初始化项目
在 make 时候出现了问题:
查了一下发现是/libsponge/util/address.hh
没有包含<array>
库
4. 反思
经历了三天的挫折,环境最终还是搭建好了,但我感觉自己在这一段痛苦的实践中收获甚微:感觉自己的信息检索能力增强了些,但具体工具的知识我却没有花时间去了解。当然我的重心还是要放在具体实验上的,如果花时间在这些“无足轻重”的事情上,或许会顾此失彼因小失大。
Part1-完成 webget
程序要求
这个webget
函数的功能就是将我们一开始手打的HTTP
请求报文写进程序里,并且发送到目的服务器,获得服务器返回的响应报文,显示在终端。
首先我们要明确两个进程连接的过程。这个过程涉及客服端/服务端的socket
创建,以及接下来的三次握手建立全双工(bi-directional)的(持续/非持续)连接。webget 只要求我们建立客户端的 socket,并和给定的目的主机host
进行连接。我们知道建立 TCP 连接需要三次握手(three-way handshake),但我们在 socket 面向应用层的这端不需要显示地对三次握手进行编程,因为这个过程交由我们的操作系统隐式完成了。不仅如此,很多轮子官方也给我们搓好了,需要我们读一下/libsponge/util
目录下的类接口(完成 webget 需要了解address.hh
、socket.hh
),也可以看官方的 library 网站。
实验过程与源码
这是我写的 webget,因为第一次做实验一开始无处下手,所以先自己凭感觉写了一次,然后借鉴其他朋友的代码进行了修改(1. 发送报文后关闭连接 2.while 判断读到文件末尾的接口)。运行./apps/webget cs144.keithw.org /hello
(根据makefile
编译的 webget 可执行程序应该在build
目录下)
1 | /*webget.cc*/ |
Part2-实现内存上的可靠字节流
实验要求
为了在内存上实现一个字节流,我们首先需要补充对ByteStream
类的定义,再实现相应的类方法。我们需要一种数据结构来模拟接收端的缓冲区(buffer),我选择的是deque
双端队列来抽象。其次还要两个数据成员total_written
和total_read
表示这个在字节流上的总读取/写入的数据量。后面我在写end_input()
和input_ended()
方法时卡住了,还是关于如何判断字节流已经读到了末尾。参考了一下其他朋友的代码后才发现,字节流是否到结尾也是需要自己模拟的,所以又添加了end_stream
成员表示字节流是否关闭。
The byte stream is finite: the writer can end the input, and then no more bytes can be written. When the reader has read to the end of the stream, it will reach “EOF” (end of file) and no more bytes can be read.
1 | /*byte_stream.hh*/ |
调试过程
我使用 VScode 的 CMake 插件进行测试用例的调试。最开始的实现六个测试一个都没通过,修改了一下类定义后只过了byte_stream_construction
测试,也就是说我的方法实现有很大的问题。下面是byte_stream_capacity
测试用例的调试,可以看见maximum
居然是一个很大的数字,后面一看是 maximum 写错了。我想用maximum
表示剩余的缓冲区空间,却错写成了stream.size()-data.size()
(已写入的数据减去待写入的数据,我也不知道什么意思…),因此造成了数值溢出!
接下来继续用测试用例 debug 修改了几个错误后,终于实现了字节流 😭!!
1 | /*byte_stream.cc*/ |
总结
虽然实验起步的阶段踩了非常多的坑,但自己却从没想过放弃,碰到问题就一定要去解决问题,因为这些都是必须要面对的,尽管解决问题的过程非常消磨人的精力,不过在痛苦之后能确切地感觉到自己真的变强了。九层之台起于垒土,或许内功的增长取决于平常解决问题收获的点滴。
为了做计网实验,我实在是花了绝大部分时间在学习其他“知识”,而非学习网络知识本身。
在从别人仓库拉 start code 时,之前在搭建博客学习的 git 都忘了很多,才发现自己其实很不了解这个工具,因此看missing semester
重新学了一边 git。在项目构建阶段,由于不明白 cmake 和 make 编译失败的原因,在解决完问题后了解了一下 CMake 工具,同时看官方的CMakeLists
,也就大概明白配置文档所写内容的含义是什么了。编写代码阶段,由于我根本不会 C++面向对象的特性,所以还花了很多时间学语言,同时也是对着类库看接口,也更清楚地明白构造函数、继承、虚函数等语言特性。
历时两周多终于完成了第一个 lab,不过我觉得这些时间花的都是值得的,让我了解到了理论知识以外的实践知识。希望接下来能更加熟悉整个编写调试的过程,善始善终完成整个大实验。