CS144 Lab1 学习笔记
CS144 是一门关于计算机网络的斯坦福大学的公开课。课程的实验是动手写一个用户态的 TCP 协议,本文是第二篇。
-
课程链接: https://cs144.github.io/
-
本文讲义: https://cs144.github.io/assignments/lab1.pdf
-
本文相关代码: https://github.com/hexyoungs/tcplab/tree/lab1
背景知识
数据在网络中的传播是字节流,字节流会被切分为不同大小的数据包,这些包在网络中传输。在网路中,每个包的传输速度、传输路径等等都是不可控的,因此数据包到达的顺序也是不可控的,所以 TCP 协议需要完成这些数据包的重组工作。
讲义
Lab1 算是开篇,介绍了我们实现 TCP 协议的策略,即模块化地实现它,并且划分了接下来几个 Lab 的主要内容和需要实现的模块。
Lab1 的内容是实现一个 Stream 的重组器(reassembler),接收一堆字节片段,然后将他们重组成为顺序正确,完整的内容。
要点
首先简单转换一下问题:输入字符串片段和它们所在的位置,输出一个完整有序的字符串。
这是关键的函数签名
void StreamReassembler::push_substring(const string &data, const size_t index, const bool eof)
index 是 data 的第一个字节在原数据的位置,假设所有数据按照正确的顺序到达,并且不存在重传的数据包,那么就什么都不用管,直接往目的地写数据就行了。
为了达到这种假设
- 首先,可以使用最小堆,每来一条数据,就按照 index 插入进堆,如果堆顶部数据的 index 正好是需要的,那就取出来,写到目的地。如果不是,说明想要的数据片段还没有到,还需要再等等。
- 其次要考虑到边界情况,比如包可能产生重传,也可能出现 overlap 的现象
整体按照这个大思路,使用测试用例作为辅助,实现即可。
碎片笔记
实现过程中,下面几点是我个人不太熟悉的部分
- 使用
make_heap
,push_heap
,pop_heap
操作的目标是一个复杂对象时,可以传入自定义的比较器。 - 使用
pop_heap
还需要配合容器的 pop 比如配合 vector 的pop_back
。 - 想要截取子字符串一定要通过 string 的
substr
方法,不要试图直接利用c_str
的内容加 offset 的方式,这样可能会丢失需要写入的数据(debug 了好一阵子才发现)。
结语
Lab1 需要实现的接口依旧很少,需要考虑的更多是边界情况,有测试用例的情况下还是相对容易的。难度开始递进了,期待下一个 Lab..
另外,完整实现在 repo 的 lab1-ans 分支供同学们参考。