CS144 - lab 0
date
Nov 25, 2022
slug
cs144-lab0
status
Published
tags
计算机网络
summary
简单的热身运动
type
Post
简介环境2 Networking by hand2.1 Fetch a Web page2.2 Send yourself an email2.3 Listening and connecting3 Writing a network program using an OS stream socket3.1 Let’s get started —— fetching and building the starter code3.2 Modern C++: mostly safe but still fast and low-level3.3 Reading the Sponge documentation3.4 Writing webget4 An in-memory reliable byte stream总结
简介
我跟的是 Fall 2021 的课程
本次 lab 对应 week 1,阅读资料都是一些基本的网络概念,这里就不介绍了,感兴趣可以自己翻阅一下
环境
我的是 m1pro 的 mbp,用 pd 开了一个虚拟机,然后用 vscode ssh 链接进行 coding
首先是安装环境
下面就可以愉快的学习了
2 Networking by hand
finish two tasks:
- retrieving a web page
- sending an email message
这些任务依赖于一个叫做 reliable bidirectional byte stream 的网络抽象
2.1 Fetch a Web page
两个操作:
- 在浏览器中访问 http://cs144.keithw.org/hello,并观察结果
- 输入
$ telnet
cs144.keithw.org
http
等待链接建立后,输入以下命令并观察结果
我们请求命令的含义分别是:
GET /hello HTTP/1.1
,告诉 server 我们想要访问的 URL 路径,这里是/hello
也就是我们的请求行
Host: cs144.keithw.org
,告诉 server 我们想要访问的 host,指的是http://
到/hello
中间的数据
完整的路径是
http://cs144.keithw.org/hello
Connection: close
,告诉 server,一旦返回结果就可以立即关闭
像这种
K:V
型的数据就是请求头啦输入后得到结果,cool
这里有一个任务
就是按照上面的流程走一遍,我不知道SUNet ID在哪里获取,我自己随便打了一个
注意看header里面的字段,确实有一个997480的值返回
2.2 Send yourself an email
用 smtp(Simple Mail Transfer Protocol)协议给自己发一封邮件
这个环节需要用 standford 的网络环境才能完成,跳过了
2.3 Listening and connecting
下面用
netcat
和 telnet
来做一个双向通信- 用
netcat -v -l -p 9090
来监听 9090 端口
- 在另一个 terminal,用
telnet localhost 9090
来链接 9090 端口
然后你会发现它们可以双向通信了
3 Writing a network program using an OS stream socket
3.1 Let’s get started —— fetching and building the starter code
运行
git clone
https://github.com/cs144/sponge
下载lab的源代码文档里面的准备工作写得很详细,我自己没有遇到问题,可以直接进入3.2了
3.2 Modern C++: mostly safe but still fast and low-level
又到了喜闻乐见的 C++ 环节,课程用的是 C++ 11,课程提出了一些要求:
- 尽量避免使用成对操作,比如说 malloc/free, new/delete,因为后面的操作可能会因为异常或者提前退出而不能正确执行
- Resource acquisition is initializatio(RAII)风格
- 设计一个类封装资源
- 在构造函数中初始化
- 在析构函数中执行销毁操作
- 使用的时候声明一个该对象的类(而不要使用new)
具体分为四步
下面还有一些规范,这里就不翻译了:
3.3 Reading the Sponge documentation
ok,然后这边给了几个文档读
这里给了官方文档说明,主要是四个类要我们阅读
- FileDescriptor ⇒ Socket ⇒ TCPSocket
- Address 是 Socket 需要绑定的地址类
- 然后看这个 libsponge/util 里面有源码
3.4 Writing webget
接下来就可以愉快的写代码了,第一个任务呢只给了我们一个函数,要求我们补全它的功能。
注释写得很详细,同时这里文档也给出了一些提示
怎么做的我们先看注释
首先注释要求我们去链接
http
service,那么自然我们需要绑定Address
,看一下它里面的构造函数。这个看起来符合我们的要求,这里也给了提示,
http
是80端口,另外/etc/services
文件包含网络服务和它们映射端口的列表。详细介绍可以看: Services (網路服務設定檔) - 維基百科,自由的百科全書 (wikipedia.org) 技术|理解 Linux 中的 /etc/services 文件
我们看看里面的说明,果然http是绑定到了80端口,而https绑定了443接口,根据协议还分为基于tcp的https和基于udp的https(也就是HTTP/3)
那么我们简单地使用
Address addr(host, "http");
获取一个地址,回头继续看文档,还提示了我们用TCPSocket,经过一番摸索之后终于理解了这个get_URL的含义:- 用TCPSocket链接指定的host,然后写入相应的请求,并打印返回值
通过测试了:
内容其实就是开始的时候,让我们手写HTTP请求获取结果一样,这里写了一个GET的请求,还有请求头说明host和connection的方式
比如我们用写好的函数,测试
cs144.keithw.org
/hello
,也能够得到正确的结果4 An in-memory reliable byte stream
接下来要我们实现一个An in-memory reliable byte stream,特点:
- 长度限制writer写入的数量,但是并不限制整个传输的信号量。
- 当writer写入到limit的时候就不能再写了,只有reader取出数据才能继续写,就像生产者和消费者模型一样。
writer的接口:
reader的接口:
实现的地方在
libsponge/byte stream.hh
and libsponge/byte_stream.cc
想了一下,这个需求双端队列应该很好写,write往队首写,reader向队尾取,队列的size提前给定了
注意到文档没有给出边界情况怎么处理:
- reader想要读取的字符长度超过了队列的大小,应该怎么处理,直接报错还是直接读取尽可能大的字符?
- 我写入的字符串大于队列大小,应该丢弃多余的字符,还是保存下来再写入?
文档开头也说了,本次课程的实验部分的需求不会写得很详细,需要我们自己摸索然后设计一个解决方案,这是因为以后工作的时候遇到很多需求都是很模糊的,这么做是为了提前训练学生的设计能力。
想了一下,这是一个经典的生产者消费者问题,用双端队列能够很好的满足我们的需求
- writer在队头写,reader取队尾
- 限制最大存储容量cap,通过队列元素个数和cap计算得到剩余可以写入的元素个数
除此之外有几个要注意的地方
- eof 表示 reader 是否读取结束,状态由队列当前元素个数和 writer 是否写入结束共同决定
- pop_output 同样也要计算读取个数
搞清楚之后实现还是很简短的,跑了一下,都通过了
debug技巧
测试文件位于tests文件夹中,点进去能直接看到测试用例和预期结果,每个测试用例还会提示你完成了多少命令,在哪一个命令出错了,通过这种方式可能节省很多debug的时间。
总结
lab0 整体上是一个热身运动
- 通过 linux 自带的指令体验了一下 http 请求
- 要求我们自己实现一个简单的 get_URL 函数去发送请求并获取结果,涉及到 Socket 和网络通信的基本知识
- 最后的 An in-memory reliable byte stream 要求我们实现了一个生产者消费者模型,还是比较有意思的