# CS144-Introduction to Computer Networking **Repository Path**: fragile_xia/cs144-introduction-to-computer-networking ## Basic Information - **Project Name**: CS144-Introduction to Computer Networking - **Description**: 一个基于RFC793的简易实用TCP套接字的实现 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2023-03-27 - **Last Updated**: 2023-04-07 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ### 0.介绍 - 文件说明 ``` apps # 应用层函数 CMakeLists.txt # 构建脚本 doctests # 内置函数测试脚本 libsponge # 应用层函数 tests # lab测试脚本 build # 构建文件 compile_commands.json # 编译命令 etc # 配置文件 README.md # 使用文档 writeups # lab0-4的文档极详细文档 ``` - 使用说明 - 创建build文件夹 ```shell mkdir build ``` - 自动生成makefile ```shell cmake .. ``` - 构建 ``` make ``` - 运行可执行文件 ```shell make check # 测试实现结果 ./apps/tcp_benchmark # 测试带宽 ./apps/wegebt # 获取网页 ``` ### 1.前言 - 同样的项目曾经在21年做过一次,当时由于时间有限加上能力不够,磕磕绊绊写完了lab0-3。但做到lab4的时候由于概念理解不清加上官网文档过于复杂实在做不下去了。 - 最近时间比较宽裕,于是又花了一周的时间重写了一遍整个lab0-4,详细的记录了整个实验过程,做完之后不禁感叹整个实验设计的精妙,通过一步一步的完善代码,难度逐渐递进,实现了一个简单但又实用的基于TCP的套接字,可用于获取网页,也可用于socket双方的通信。 - 如果你有以下疑问,那么通过完成整个lab可以解决你的疑问。 - TCP的**MAX_PAYLOAD_SIZE**只有1536字节,为什么可向socket一次性写入**1M**的数据? - 对socket一次写入n字节的数据,而对另一端一次性读取socket得到m字节的数据,n和m一定相等吗?为什么n和m有时候是不相等的? - TCP是如何进行流量控制的? - 为什么TCP需要三次握手?四次挥手? - 什么是time-wait状态?为什么time-wait状态后还需要等待2个MSL? - client和server应用程序如何判断对方已经关闭连接?为什么要这样判断? ### 2.实验简介 #### 2.1 lab0 networking warmup - 熟悉整个lab实验环境 - 用操作系统socket接口编写网络程序 - 实现一个可读可写的缓冲区 #### 2.2 Lab1 stitching substrings into a byte stream - 实现一个字节重组器 - 将字节重组器与缓冲区相联系起来 #### 2.3 Lab2 the TCP receiver - 32bit数-64bit数之间的转换与舍入 - 根据收到的报文段返回相应的ackno和win窗口字段值 #### 2.4 Lab3 the TCP sender - 将上层(ByteStream)发来的数据切片(写seqno,SYN,FIN,payload) - 维护一个计时器工具类 - 基于计时器类维护已发送的报文段 - 在适当时机重发上述报文段 #### 2.5 Lab4 the TCP Connection - 将网络层收到的报文传递给TCP sender和receiver - 在合适的时机将报文发出 - 将TCP sender待发送的报文添加字段发送出去 - 在合适的时机结束连接 ### 3.实验须知 - 实验前需要对c++11面向对象编程有一定的了解。 - 整个lab绝大部分不懂的地方都可以从https://cs144.github.io/官方文档上获取,现在所有的代码和文档都已经开放,均可clone到本地。 - 整个实验ip层仍然基于linux的实现,ip层通过暴露两个接口与tcp_connection进行交互。 - 文档上会有少数一些摸棱两可和重复的描述,这时可以通过看到官方RFC文档来解决疑问,也可以有一些自己的尝试。 - 如果读完官方文档后,仍然一头雾水的话,可以提前查看少数对应该lab的测试用例。 - 在前面几个lab中尽可能完备的设计,为最后的lab4作铺垫,防止lab4中还要修改前面出现的bug。 - 在lab1中,需要尽可能设计高效的数据结构,不然可能在lab4中无法通过测试。 - libsponge/util中可能会有一些实验中能够用到的类,用于提高效率。 - 整个lab中调试语句用cerr代替cout打印中间变量,在lab4测试中需要删除打印语句,否则可能出现一些奇奇怪怪的错误。 ### 4.实验结果 #### 4.1 基于tcp_connection的客户端服务端交互过程抓包 - 三次握手 ![](https://gitee.com/fragile_xia/git_test/raw/master/3.27/1.png) - 数据传输 ![](https://gitee.com/fragile_xia/git_test/raw/master/3.27/2.png) - 四次挥手 ![](https://gitee.com/fragile_xia/git_test/raw/master/3.27/3.png) #### 4.2 基于benchmark的测试 ![](https://gitee.com/fragile_xia/git_test/raw/master/3.27/4.png) - 已经超过讲义中要求的0.1Gbit/s, 考虑到仍有一些libsponge/util中的工具类没有使用,还有很大的优化空间,后续会对此继续进行优化。 #### 4.3 基于自己实现的socket获取网页 - webget.c ```c++ void get_URL(const string &host, const string &path) { // 基于自己实现的socket CS144TCPSocket sock; sock.connect(Address(host, "http")); string url = "GET " + path + " " + "HTTP/1.1" + "\r\n"; url += "Host: " + host + "\r\n"; url += "Connection: close\r\n"; url += "\r\n"; sock.write(url); constexpr size_t BUFFER_SIZE = 1024; string buf; while (!sock.eof()) { sock.read(buf, BUFFER_SIZE); cout << buf; } sock.wait_until_closed(); } ``` - 运行结果 又回到最初的起点lab0 ![](https://gitee.com/fragile_xia/git_test/raw/master/3.27/5.png)