Skip to content

FF-crazy/CS144

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

34 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Stanford CS 144 Networking Lab 感想与经验

总体概述

  • 我写的版本是2024年的minnow,全部是用C++写的,官网在这里,我自己实现的作业
  • 推荐阅读 计算机网络:自顶向下方法,由于视频来源自N年前的东拼西凑的老古董,以及老师的讲课风格我很不喜欢()让我看得昏昏欲睡,不推荐看网课。
  • 课程lab一共有8个,每个lab都有一个主题,下文我会详细说一下,主题是自己实现一个TCP/IP的协议栈(包括ARP协议),但是又没有从零开始,minnow已经把大部分框架都帮你做好了,你只需要去修修补补就够了;类似于代码填空,在某个地方填某个东西让代码跑起来。
  • 终于到lab精华的部分了,与国内大学的古董C++教程相比,minnow才是真正的modern C++,通篇采用C++20标准,使用现代化的编译工具链(cmake),让我感受到现代工程是怎么样的,也让我下定决心,以后非必要再也不写C++(具体原因后面说),同时,lab还要求
    • 不使用任何模版,虚函数等C++独有的花活
    • 不使用newdelete关键字
    • 禁止使用裸指针,如需使用指针,必须用std::shared_ptr<>std::unique_ptr<>(用RAII自动gc真痛快)
    • 不准使用C风格的函数,比如char* str
    • 不准使用C风格的强制转换,必须用C++的static_cast<>等等
    • 变量能加constconst,尽量减少变量的作用域
  • 可惜没用上C++23,不然我就写C Python Plus了
import std;
int main() {
  std::println("Hello, world!");
}
  • 我只在学校里学过C++11,自己写的C++,也就是C with STL&class,初次写这个项目的时候非常痛苦,因为一半函数都看不懂(),但是lib都是给你编译好的二进制文件,导致IDE Ctrl+左键点进去以后我看到的是这样的
#if __cplusplus >= 201103L
      _GLIBCXX20_CONSTEXPR
      void
      push_back(value_type&& __x)
      { emplace_back(std::move(__x)); }
  • 主打的就是啥也看不懂,什么std::optional什么std::span(args, argv)全是看不懂新语法,我刚开始写的时候一半时间都在查这个函数是干嘛的,好在课程推荐看指南C++已经日新月异,每个人必须学亿万语法,也是让我下定决心以后不写C++,这语言怎么这么丑陋,感觉就是在依托史山上缝缝补补的作品,难怪能进白宫优选。包管理器,你在哪里?
  • 不过,lab的缺点也是显而易见的,本课程的所有lab主打的就是一个面向测试用例编程,所有的项目文档都好像是写了,但是又好像什么都没写(教授说这是这是模拟你们上班当牛马以后领导给发的文档,我想问问已经上班的各位文档真有这么写的吗?)只有部分文档写的还可以,有cs61b那种面面俱到的水平。这一系列lab还是有些高屋建瓴了,很多地方就差一点,所有的lab都是点到为止,比如lab0-lab3实现了完整TCP协议,但是就差临门一脚的三次握手和四次挥手,到此为止了,导致我们在lab3里实现的每种case没有被直观的利用,有点遗憾。
  • 还有一个弊端,就是为了能统一测试用例,所有的需要你完成的接口都被定的特别死,还有很多util里的类的字段都不让改,很多我觉得改改接口或者加个成员就能更好实现的地方不让改,让我很难受。由于很多lab之间有依赖关系,如果你某个lab没得满分,那后面的lab会受到不好的影响。史山代码生成器
  • 课程是不让用AI和看别人的实现的,老实说,我两个都干了(),不用AI debug是真的头大(现代工具还是要用的),很多东西文档根本没写清楚,我也根本看不懂他要我干嘛,看了别人代码我才知道要干嘛,还是太隐晦了()。

每个lab的粗略具体介绍

  1. lab0是一个热身lab

    • 先用古董telnet写一段简单的普通的http message,请求学校服务器得到http 200,(telnet是明文传输,我们都用ssh),很简单,按照doc做就完事了。
    • 接下来需要你仔细读当前实现的代码,利用GNU/Linux提供的接口实现一个基于TCP协议的顶层webget应用,以后会换成我们自己实现的。
    • 接下来就是重中之重,本项目的上层接口ByteStream,lab的设计很有意思,由于websocket是双工的,必须实现读和写,于是lab的设计是写一个基类存byte,然后通过继承产生ReaderWriter,用的时候就互相强制转换,我自己的个人设计想法是写一个类存byte,然后分别写两个静态类Reader和Writer,通过静态方法实现读写操作。
    • 完成之后有一个benchmark,文档说你要是设计的好,速度能超越10Gbps,我自己的实现只有2.46Gbps,属于比较拉的了,不过lab要求只需要大于0.1就行,所以我就没继续优化了()。
  2. lab1要你开始深入TCP协议的底层,写一个重排器,

    • 本质上是用一点算法小知识,让你写一个集合,实现交并运算。
    • 虽然是为数不多写的文档还算好的lab,但是此时面向测试用例编程就已经初现端倪了,写的时候很多坑,最让我印象深刻的是:当来的字节流是最后的片段(有终止flag)但是超出bytestream的容量以后,要直接截断字节流,但是要保持字节流是开放状态,我当时不知道,无脑关了,于是测试用例急眼了()后来我才意识到,TCP是一个管生又管养的娘,网络层和链路层高情商说是尽力发送,低情商就是全都做不到,必须由TCP负责,否则就会丢包。
    • 也让我感觉现代计算机网络也是史山(),下层不负责任,上层就得费劲心思。学院派的七层结构更是只存在课本里,因为有太多东西是出现下层依赖上层(比如TLS,openflow),就算改成四层五层也救不了,最新的HTTP3更是演都不演了,QUIC都把应用层和运输层合二为一了(我的碎碎念)。
    • 这个lab也有一个benchmark,要求和lab0一样,我实现的速度是5.76Gbps,算法大手子应该能到超过10Gbps。
  3. lab2要你实现Wrap和TCP的接收方

    • 先说wrap,由于TCP头部的seqno是32位的,但是我们的bytestream是64位的,我们利用参考值转换位数,文档写:如果网速是100gbps,那么占满32位需要1/3秒,占满64位需要大约50年,其实就是一个简单的算法题,寻找离checkpoint最近的某个数,不难。
    • 再说TCPReceiver,需要你实现TCP的接收方,针对各个情况(SYN, FIN, RST),接收来着lab1的重排器的segment,然后做出回应(回答正确的ack,要求续传或重传)。
    • 这个测试非常棒,不仅面面俱到,同时甚至贴心的详细给出了每个样例具体挂的原因是什么,我非常喜欢这样的测试框架,精致优雅且有效。
  4. lab3让你实现TCP发送方,是这个项目最难的部分,也是所有lab的精髓

    • 和TCP接收方相反的是,你需要接受来自上层的信息,往下传递,需要在内存维护一张表,监控所有已经发出但没有收到 ACK 的消息,也需要写一个tick函数,为了确保能送到,需要写触发重传的机制,还有重传次数过多后放弃续传,报告失败。
    • lab的重传机制逻辑比较简单,和现实的比较复杂的自适应算法不同,就是简单的指数递增,接受ack后重置。当然现实中的重传计时器为了性能的综合考虑,设计的也很傻,无脑重传seqno。
    • 面向测试用例编程发力了,坑非常多,比如初始时候认为接收方window size是1(文档有仔细写,但我没看到),我们什么时候能确认发送端的 FIN ,要特别注意如何处理长度为 0 的 window size(答案是为了避免死锁,要立即开始重传计时),尤其是当处理 RTO + timer 的时候
    • 这个lab让我写的很痛苦,刚开始写的初版很快,然后光速wa,此后一直在痛苦的调试,导致我的代码框架非常丑陋,到后面几乎就是各种if else的组合,以至于让我下决心重构(虽然只重构了一部分),我承认,最后100% test pass的时候我是很爽的。
  5. lab4让你测量真实世界的网络,不用写代码,这里跳过论述。自此,已经完成了所有TCP协议的部分,我们要逐步把Linux提供的接口改成我们自己的。不过,这也是我所说的可惜的地方,本来这里应该是临门一脚的,彻底实现TCP握手和挥手,但是lab却在这里戛然而止,把这一通流程全帮你实现了,有点可惜,本来我们有机会把前几个lab所实现的(其实是代码填空)都串起来,实现自己的TCP over IP。

  6. lab5让你开始深入链路层最底部,写一个NetworkInterface,开启本课第二部分,实现一个ARP协议,写一个MAC地址和IP地址的转换器

    • 有点贵物,写的时候犯🍬,ARP缓存超时时间多打了一个0(把3s转成了30000ms),导致我debug了一晚上都没pass,后来在GPT5老先生的慧眼识珠下,我才顺利渡劫。这让我想起了NJU jyy老师的话:

    你写的程序,没有测试的部分,一律认为有bug,真正的bug往往隐藏在你觉得绝不可能出错的部分。

    • 因此我推荐各位都去看jyy老师的金科玉律
    • lab需要你理解ARP协议的语义,了解了预设的各个字段的含义以后,其实就不难了,唯一注意的地方是当缓存里没有需要的MAC地址后,需要缓存当前的datagram,并发送一个ARP message,得到ARP reply后,要立马把缓存里能发出去的都发出去。
  7. lab6需要你来到链路层的上层,仅需要完成一个路由表,也就是实现一个最长前缀匹配的算法

    • 以往的了lab其实都比较看中工程能力和一点点算法技巧,这个lab才开始有数据结构知识,以往的复杂数据,我都是无脑vector和哈希表(哈希表真轮椅吧,感觉啥都能存,存啥都快)。这个项目要求你至少达到O(n),我一看到最长前缀匹配,就想到了字典树,C++里没有直接的容器,我就自己实现了一个(梦回数据结构)
    • 由于这个lab只让你干这一件事,导致目标和规划都异常的简单,感觉是最简单的lab了
    • lab6里有句话非常好

    There's a beauty (or at least a successful abstraction) in the Internet's design here: the router never thinks about TCP, about ARP, or about Ethernet frames.

    The router doesn't even know what the link layer looks like. The router only thinks about Internet datagrams, and only interacts with the link layer through the NetworkInterface abstraction.

    When it comes to questions like, "How are link-layer addresses resolved?" or "Does the link layer even have its own addressing scheme distinct from IP?" or "What's the format of the link-layer frames?" or "What's the meaning of the datagram's payload?", the router just doesn't care.

    • 这就是计算机之美所在了,抽象是计算机世界中难能可贵的哲学思想,通过抽象,我们能够把所有复杂的困难的东西简化成一个个简单的状态机,作为一个router,我不需要管什么是HTTP message,什么是frame,我甚至也不需要管底层是怎么样的,硬件是怎么样的,电路是怎么样的,我只需要做好我自己的事情就行了,也就是来一个ip,转发到下一跳。通过一层层的抽象,人类实现了复杂而又庞大的计算机网络。抽象就是人类伟大智慧的瑰宝。
  8. lab7让你把以往写的一切都组合起来,彻底替换linux的东西,完全用我们自研的TCP/IP栈(虽然多线程和具体的组合都帮你实现好了),由于不需要写一个字的代码,只需要保证以往的lab都没bug就行,所以就此略过。

总结

  • 整个项目的代码质量非常高,推荐大家把所有的代码都读读看,可以说是年轻人的第一门C++课。我觉得对提升工程能力很大,虽然完成全部作业也就让你写四五百行代码,重要的部分是让你去读,你必须读好作者给你写好的接口和类的声明,读懂代码,我觉得在工程里,是很重要的。
  • 项目有一个得天独厚的优势,就是全开源的框架和开放所有的测试用例,能让大家快速审查自己的代码正确性。
  • 虽然还是有点欠缺,但是我还是非常推荐大家去做,尤其是大学生,这超越了课本上的纸上谈兵,能让人自己实现这个工程理念,加深了对TCP/IP协议和ARP协议的认识,真正做到了知行合一,让你做到"Talk is cheap, let me show my code"。毕竟,计算机科学是一门理论和实践并行的显学。

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages