Lab0
本次实验一直在强调的一点就是,TCP的功能是将底层的零散数据包,拼接成一个reliable in-order的byte stream。这个对我来说非常“振聋发聩”(夸张了233),以前只是背诵地知道TCP的可靠性,这次我算是第一次知道了所谓“可靠”究竟可靠在哪:一是保证了序列有序性,二是保证了数据不丢失(从软件层面)。
还有一个就是大致了解了cs144的主题:实现TCP协议。也就是说,运输层下面的那些层是不用管的吗?不过这样也挺恰好,我正好在学校的实验做过对下面这些层的实现了,就差一个TCP23333这样一来,我的协议栈就可以完整了。
本次实验与TCP的关系:
在我们的
webget
实现中,正是由于TCP的可靠传输,才能使我们的http request正确地被服务器接收,才能使服务器的response正确地被我们接收打印。而在
ByteStream
中,我们也做了跟TCP类似的工作:接收substring,并且将它们拼接为in-order的byte stream【由于在内存中/单线程,所以这个工作看起来非常简单】:
1
2
3
4
5 while(is_input_end == false&&pointer<length){
if(buffer.size() == capacity) break;
buffer.push_back(data[pointer]);
pointer++;
}
Fetch a Web page
主要是介绍了telnet
指令
Send yourself an email
用的是telnet带smtp参
Listening and connecting
上面的telnet是一个client program。接下来我们要把自己放在server的位置上。
用的是netcat
指令。
Use socket to write webget
这个确实不难,就是这个地方有点坑:
Please note that in HTTP, each line must be ended with “\r\n” (it’s not sufficient to use just “\n” or endl).
导致我跟400 Bad Request大眼瞪小眼了好久。。。
1 | void get_URL(const string &host, const string &path) { |
还有一点值得注意的是,当我这样时:
1 | TCPSocket sock; |
会报错Operation now in progress
。
关于socket通信中在connect()遇到的Operation now in progress错误
遇到此错误是因为将在connect()函数之前将套接字socket设为了非阻塞模式。改为在connect()函数之后设置即可。
我觉得这个实验设计得挺好的,写的时候感觉很有意思。我推荐看下 https://github.com/shootfirst/CS144/blob/main/lab-0/apps/webget.cc 里的注释,写得很好很规范,让我明白了很多本来没搞懂的地方,比如说shutdown
的用法。
An in-memory reliable byte stream
实现一个
ByteStream
类,可以通过read
和write
对其两端进行读写。是单线程程序,因而无需考虑阻塞。
感想
这东西其实是很简单的,但是我还是花了一定的时间,主要原因有两点,一是我不懂c++,所以一些地方错得我很懵逼,二是因为我是sb。
下面就记录下三个我印象比较深刻的错误吧。
错误1 member initialization list
构造函数我一开始是这么写的:
结果爆出了这样的错:
搜了半天也没看懂怎么回事,去求助了下某场外c艹选手,才知道了还有成员变量初始化列表这玩意,这个东西似乎比较高效安全。
于是我改成了这么写:
它告诉我buffer
也得初始化。于是我又这么写:
又是奇奇怪怪的错误,说明vector不能这么初始化。
场外c艹选手看到了这个:
所以说vector应该这样初始化:
错误2 使用了vector
作为buffer的载体
应该使用的是可以从front删除数据的数据结构,比如说deque。【vector也行,但是效率较低】
具体为什么,可以以数据流为cat为例。执行peek(2)
时,使用vector得到的是at,使用deque得到的是ca。
错误3 错误地阻塞
一开始在write
方法,我是这么写的:
1 | int length = data.length(); |
结果就是测试用例Timeout。我找了很久都不知道错在了哪,最后求助了场外观众【罪过……这次实验太不独立了】,学着他把length改成了这样:
1 | int length = min(data.length(),capacity-buffer.size()); |
发现成了。
我去看了看testbench,猜测应该是因为阻塞了,我还以为是deque自身会阻塞【是的,我完全没注意到自己顺手把阻塞写了下去】,查了半天发现不会,最后才发现是自己不小心搞错了呃呃…………
代码
头文件声明
1 | class ByteStream { |
具体实现
1 | ByteStream::ByteStream(const size_t cap) : total_write(0),total_read(0),is_input_end(false),capacity(cap),buffer(){ } |