动手学TCP——CS144实验感想
在Stanford CS144的课程实验Lab0~Lab4中,我们动手实现了一个自己的TCP协议,并且能够真的与互联网通信!此外,感谢Stanford开源本实验并提供了大量的优质测试用例,使得我们仅仅通过互联网就能获取到这么好的学习资源。
本篇博客将从我自己的角度出发简单介绍TCP协议,阐述实现的难点以及在实验过程中的收获。
什么是TCP?
正式的定义以及计网相关的基础知识请读者自行stfw,在此我只简单地从自己角度阐述。
- 从网络协议抽象层来看,TCP是一个传输层协议,用于实现不同主机上进程与进程之间的通信。
- 从TCP提供的服务来看,TCP是可靠数据传输协议,保证将输入的数据保序、保真、不丢失地输出到指定位置。
- 从TCP的核心思想来看,TCP依托于底层不可靠的网络层协议来实现可靠传输,其中的很多设计具有深刻内涵。
TCP的设计有哪些思想?
作为对本课程实验设计者的尊重,本篇博客不会涉及具体的思路,更不会展示代码。我只想聊一聊主要方向。
在深入TCP细节之前,让我们来做一个简单的思维实验:双军问题
在一场攻城战中,己方的两位将军只能派遣信使穿越敌方领土来相互交流。信使可能被逮捕,但他们想要确定一个一起进攻的时间。请问两位将军采取什么策略才能确定一个100%两人都会进攻的时间呢?
将军\(A\)派遣信使传递消息\(M_1\),将军\(B\)收到后传递\(M_2\)回复。为了使得\(B\)确信\(M_2\)被收到,\(A\)又需要发送\(M_3\)....
可以证明,这个问题是无解的。
其实,TCP要解决的就是这样的难题。网络层协议是不可靠的,TCP为了确认数据可靠到达,不得不采取回复机制,即发送方只有正确收到接收方的回复才能确认该数据送达。但回复机制最终还是要面临上述难题————TCP的两端必须确保自己、对方都希望终止连接才能退出。
为了解决这一难题,TCP采用了工程化的办法将误判的概率降到极低。如下图所示,最后一个报文的发送方会等待一段时间(linger time). 如果这段时间里对方没有发送要求重传的报文则默认对方已收到报文。

思考:如上图所示,先接收到结束信号的主机可以不在最后等一段时间,为什么?
除了结束时的确认机制外,TCP还有很多机制确保数据可靠传输同时保证性能:
- 如上文所说的,为了确认单个报文正确送达引入应答机制
- 为了确保报文之间有序引入计数器机制
- 为了提高效率而不是“一问一答”,引入流水线机制,并通过滑动窗口、回退等技巧保证正确性
- 为了辨别报文丢失和网络拥堵,引入计时机制,同时为了不断逼近当前网络拥堵情况采用指数上升、线性下降法动态调整计时。
......
TCP是一个经典且有效的协议,其设计者早在如今的因特网普及之前就提出了相关思想并因此获得图灵奖。我们在学习网络协议的时候,更重要的是学习这个系统的抽象机制以及各抽象层的设计思想,TCP正是一个巨大的思想宝库。但由于其过于经典,关于它的文章、教材数不胜数,我就不在此一一赘述上述机制的细节了,感兴趣的读者可以自行学习。
CS144如何组织实验?
国内高校的一些课程最不合理的一点就是学习与实践分离,实践与现实疏远。下面我很主观地做一些对比:
课程主要目标:学习C语言程序是怎样最终运行起来的?
- A课程:动手写一个计算机系统模拟器,设计指令集、运行环境、简易操作系统,并最终能运行真实的程序甚至仙剑奇侠传;动手能力强的同学甚至可以用不同方式实现同一抽象层。实践占评分大部分。
- B课程:只有理论课没有实验作业,教材提供的现成模拟器运行的是自创的及其简易的指令集,只能完成一些算术运算操作。期末考背书题占比极高。
课程主要目标:学习计算机硬件组成及设计
- A课程:动手写一个芯片!如果顺利还能成功流片拿到实物。
- B课程:不依托具体指令集讲一些计算机组成中抽象的概念,作业考试大部分都是计算读写速率,平时实验虽然很贴合课程内容,但写成之后唯一的作用就是通过测试用例。
根据我的调查,美国很多大学的课程及其注重实践。比如Stanford CS144学网络,8个Lab就是实现各种网络协议,能够真正和互联网通信;CMU 15-445学数据库设计,Lab就是实现一个完整的的数据库管理系统并管理两百多万条数据......
诚然,这样的实验需要大量的精力去设计,但其对于学生的教育和鼓舞也是极大的。幸运的是国内也有很多优秀的人才做出了这方面的贡献(南大ics、os,一生一芯等)。作为一个资质平平的学生,我可能没有能力为国内计算机教育事业贡献自己,但我希望能尽自己的努力让身边的同学知道有更好的课程,计算机教育不只是自学,不只是背书,不只是调包。
下面回到正题,CS144是怎么把这个实验组织起来使得学生既不需要关注与OS、硬件等交互的细节,又能真正写出一个work的程序的呢?

这张图是他们的实验组成。
在Lab0中,我们调用Linux的TCPSocket实现了自己的wget程序
Lab1~Lab4中,我们实现了自己的TCPConnection并最终替换了上面的Socket使得Lab0中的wget运行在自己的TCP上与互联网连接。
CS144把TCP的实现分为两大部分,Socket和Connection,其中Socket由框架代码直接给出(主要涉及与底层、OS交互,不是TCP的重点),Connection又分为Sender、Receiver两部分让同学分时完成。
这样做一方面降低了实验难度,另一方面也保证了实验成果的有用性。
除此之外,CS144开源了大量的测试用例,其测试脚本编写的也及其易懂、好用,很值得学习。

CS144提供的测试用例覆盖度及其广泛,这在一定程度上确保了自己实现的TCP的鲁棒性。每个实验都会用到之前的代码,很多之前已经通过的代码之后还会找出BUG。在完成Lab4后,大量的测试用例模拟了真实网络环境中的各种情境,如果没有真正理解TCP的每一处细节,很难通过。最后,在自己写的协议上与互联网通信,既是一种收获,也是一次测试(是的,即使通过了所有用例还可能会出现新的bug).
总而言之,CS144通过合理的抽象让学生关注于任务的重心,通过划分降低实验难度,提供大量用例提升实验质量,最终成果也让人颇感欣慰。
总结
- 这几个实验其实代码量并不大(一共不超过500行),但花了我三四天的时间。现在想来,还是没有在一开始理解TCP的很多细节,做的时候存在大量的面向用例编程行为。
- 这次实验再次让我明白了基础设施的重要性(看来PA还是没吃够苦头),gdb、wireshark等设施也是后面printf大法不管用才想起来。
- 通过这次实验,我更坚定了自己学以致用的学习策略。即学到了什么通过实践检验,学得怎么样通过实践效果评判,不读死书。因此之后可能会开数据库的新坑...
- 再次感受到自己能力的不足...还需要再努力寻找更好的学习方法呀
我的水平有限,以上各部分内容难免有疏漏、主观臆断的部分,如有错误、冒犯请指出,感激不尽!
感谢你能看到这里,或许看了上文你会觉得有一点共鸣,有一点共同探讨的欲望。我非常非常欢迎、期待与志同道合的朋友一起学习!在此之前,我简单的自我介绍一下:
我来自南京大学软件学院本科二年级,是一个智力平平但渴望用努力弥补缺陷的人,目前的愿望是能在大学本科期间更了解自己、更了解这个社会运转的规律、找到自己喜欢的事业并为之奋斗。目前在计算机领域没有什么特长,但希望能共同学习进步!邮箱:heiyan2020@gmail.com/QQ:370349370
动手学TCP——CS144实验感想的更多相关文章
- 自己动手学TCP/IP–http协议(http报文头)
在前面的一篇文章中,简单了介绍了HTTP报文格式,详情参考http://www.firefoxbug.net/?cat=47. 这里大概介绍下基本的,常见的HTTP包头格式. POST /report ...
- 动手学习TCP:总结和索引
TCP是一个十分复杂的协议,通过前面几篇文章只涉及了TCP协议中一些基本的概念. 虽然说都是一些TCP最基本的概念,但是试验过程中一直在踩坑,例如:TCP flag设置错误,seq.ack号没有计算正 ...
- 动手学习TCP:TCP特殊状态
前面两篇文章介绍了TCP状态变迁,以及通过实验演示了客户端和服务端的正常状态变迁. 下面就来看看TCP状态变迁过程中的几个特殊状态. SYN_RCVD 在TCP连接建立的过程中,当服务端接收到[SYN ...
- 动手学习TCP:数据传输
前面的文章介绍了TCP状态变迁,以及TCP状态变迁图中的一些特殊状态. 本文主要看看TCP数据传输过程中需要了解的一些重要点: MSS(Maximum Segment Size) Seq号和Ack号的 ...
- 动手学习TCP:4种定时器
上一篇中介绍了TCP数据传输中涉及的一些基本知识点.本文让我们看看TCP中的4种定时器. TCP定时器 对于每个TCP连接,TCP管理4个不同的定时器,下面看看对4种定时器的简单介绍. 重传定时器使用 ...
- 动手学习TCP:数据传输(转)
前面的文章介绍了TCP状态变迁,以及TCP状态变迁图中的一些特殊状态. 本文主要看看TCP数据传输过程中需要了解的一些重要点: MSS(Maximum Segment Size) Seq号和Ack号的 ...
- 动手学习TCP:TCP连接建立与终止
TCP是一个面向连接的协议,任何一方在发送数据之前,都必须先在双方之间建立一条连接.所以,本文就主要看看TCP连接的建立和终止. 在开始介绍TCP连接之前,先来看看TCP数据包的首部,首部里面有很多重 ...
- SSH服务与tcp wrappers实验
SSH服务与tcp wrappers实验 实验环境: 一台linux(ssh client) 一台linux(ssh server) 实验步骤: 1.配置IP,测试连通性 2.在客户端创建用户yuzl ...
- 脑残式网络编程入门(一):跟着动画来学TCP三次握手和四次挥手
.引言 网络编程中TCP协议的三次握手和四次挥手的问题,在面试中是最为常见的知识点之一.很多读者都知道“三次”和“四次”,但是如果问深入一点,他们往往都无法作出准确回答. 本篇文章尝试使用动画图片的方 ...
随机推荐
- JavaScript数据结构之链表
链表相较于数组的优缺点 1. 链表在 插入.删除.移动数据效率比数组要高,数组插入.移动.删除数据需要改变没有数据的索引,而链表则只需要更改指针即可 2. 在查询方面,数组要优于链表,数组存储的数据是 ...
- 趁着同事玩游戏偷偷认识k8s一家子补补课
趁着同事玩偷偷认识k8s一家子补补课 Kubernetes集群这个大家庭在容器化时代能够新军崛起,要感谢其众多可靠稳定,工作认真负责的优质成员. 这些兄弟姐妹们为集群提供故障转移和高可用性,保证k8s ...
- Spring事物
简介 Spring并不直接管理事务,而是提供了多种事务管理器,他们将事务管理的职责委托给Hibernate或者JTA等持久化机制所提供的相关平台框架的事务来实现. Spring事务管理器的接口是org ...
- Idea中新建package包,却变成了Directory
问题描述 今天在IdeaJava工程src下新建了一个名字叫包implements的包,右键在里面新建类时,却发现根本就没有Class这个选项,然后发现implements这个包的图标也和其他包的图标 ...
- 一键部署lnmp
一键部署lnmp 提前将nginx .mysql .php 所需安装包都放在/opt目录下 脚本启动结束时,重启一下nginx 服务,就能在火狐浏览器更新出php测试页 脚本如下:(脚本里的软件 ...
- 014 Linux 线上高频使用以及面试高频问题——如何查找大文件并安全的清除?
目录 1 案例描述? 2 命令一(目录统计排序最佳命令) 3 命令二(最实用,目录和文件一起统计排序) (1)命令详情和说明 (2)du.head.sort.awk 详细说明参考已有文章附录 (3)L ...
- asp.core 同时兼容JWT身份验证和Cookies 身份验证两种模式
在实际使用中,可能会遇到,aspi接口验证和view页面的登录验证情况.asp.core 同样支持两种兼容. 首先在startup.cs 启用身份验证. var secrityKey = new Sy ...
- 流程控制( if while )
目录 流程控制 必知必会 分支结构 if 1.单 if 分支结构 2. if与else连用 3. if, else和 elif if 判断之嵌套 if 练习题 while 循环 while+break ...
- linux下gdb如何处理coredump错误
linux下gdb如何处理coredump错误 在编写C++程序中,我们经常会遇到一种错误,segment fault, 这种coredump错误 会导致程序运行时异常退出或者终止,这种错误没有明显错 ...
- Linux上大文件切割以及批量并发处理
一.环境说明 某次项目需求中,在Linux上有批文本文件,文件文件都有几个G大,几千万行的数据.无论在Linux和Windows打开这么大的文件,基本上打开要卡半天,更别说编辑. 因此想到使用spli ...