standford cs144计算机网络Lab1-实现字节流重组器

发布时间:2026/8/1 5:53:35

standford cs144计算机网络Lab1-实现字节流重组器
书接上回打开终端在项目目录之中输入git checkout -b mylab1 origin/lab1-startercode可以获取纯净的lab1原始代码建立属于你的lab1的分支就可以在操作台上面写代码了。通过git merge mylab0将上一个实验的实现内容合并到当前分支本实验依赖lab0实现的Bytestream。初始化构建方法mkdir build cd build cmake .. make -j4一、实验任务和原理计算机网络采用分层设计底层服务通常只提供较低的可靠性保障。以网络层的IP协议为例它仅承诺“尽最大努力”交付数据包但数据包在实际传输过程中可能面临丢失、乱序、重复或内容损坏等问题。而上层的应用程序总是希望看到一条可靠的、连续并且顺序正确的数据流TCP则是其中的经典案例他在底层网络只提供“尽最大努力”的数据包传输服务之上为通信双方提供可靠的字节流服务能够让通信双方看到可靠有序的字节流。在lab1中我们将实现streamReassembler模块实现TCP能够将字节流片段拼接成为可靠的连续的原始流的能力。streamReassembler主要需要我们完成保存乱序的片段去除重合和重叠片段将他们重新组装成为正确的顺序并且写入我们在lab0之中实现的bytesteream之中。在本实验之中会出现以下核心接口需要我们完成设计// Construct a StreamReassembler that will store up to capacity bytes. StreamReassembler(const size_t capacity); ​ // Receive a substring and write any newly contiguous bytes into the stream, // while staying within the memory limits of the capacity. Bytes that would // exceed the capacity are silently discarded. // // data: the substring // index indicates the index (place in sequence) of the first byte in data // eof: the last byte of this substring will be the last byte in the entire stream void push_substring(const string data, const uint64_t index, const bool eof); ​ // Access the reassembled ByteStream ByteStream stream_out(); ​ // The number of bytes in the substrings stored but not yet reassembled size_t unassembled_bytes() const; ​ // Is the internal state empty other than the output stream? bool empty() const;这些提供的接口也就是stream_reassembler的函数成员作为公共成员向外提供操作。头文件之中给定的私有成员ByteStream _output; //! The reassembled in-order byte stream size_t _capacity; //! The maximum number of bytes_output是内部输出的有序字节流_capacity是可容纳的最大容量。实验handout也对capacity这个成员变量做出了相关的解释。capacity不仅单纯限制缓存的接收到的乱序数据也包括ByteStream当前保存的还没被读走的数据是对内存使用的限制所以存在以下关系ByteStream 中尚未读取的字节数 StreamReassembler 中未组装字节数 capacity可以接收的窗口范围通常是[first_unassembled, first_unacceptable)其中first_unassembled 已经成功写入 ByteStream 内容的下一个字节下标 first_unacceptable first_unassembled 剩余可用容量凡是落在这个范围之外的字节都应该丢弃。图示如下需要处理的关键场景按序到达push_substring(ab, 0) 立即写入 outputoutput 中有 ab push_substring(cd, 2) 紧接着output 中变成 abcd这是最简单的情况当前期待的下一个字节刚好达到乱序到达空洞push_substring(b, 1) 还没收到 index0 的字节先存起来output 为空 push_substring(a, 0) 现在 0 和 1 都有了组装 ab 写入 output这里需要一个数据结构来暂存早到的片段重叠片段push_substring(abc, 0) output: abc push_substring(bcd, 1) bc 与已有数据重叠d 是新的 → output: abcd push_substring(cdef, 2) cd 重叠ef 是新数据 → output: abcdef新到达的片段可能出现部分或者全部和已经存储或者已经输出的数据重叠在这里需要精准的裁剪重复片段push_substring(abcd, 0) output: abcd push_substring(abcd, 0) 完全相同应被忽略unassembled_bytes 不变 push_substring(ab, 0) 是已有数据的前缀子集应被忽略重复片段是不应该被重复写入的容量限制capacity 2 push_substring(ab, 0) → output 有 ab占满容量 push_substring(cd, 2) → 超出容量cd 被丢弃或部分丢弃总容量等于bytestream之中未读的字节加上未组装暂存的字节超出的部分应该按照要求丢弃。eof处理push_substring(b, 1).with_eof(true) 虽然 eoftrue但 index0 还是空洞 push_substring(a, 0) 现在 ab 写入并且此时才设置 output 的 EOF即使eoftrue也必须要等到前面的所有字节都按照顺序写入值得注意的是测试样例里面存在大规模随机测试样例考验我们对于数据结构存储的选择。以上这些场景在给定的测试框架之中都有相关的测试样例我们选取的数据结构以及实现的方案需要成功处理所有的样例。二、数据结构选取和设计方案需要实现的核心文件是stream_reassembler.hh和stream_reassembler.cc头文件之中增加需要的成员变量并且在实现文件之中将给定的函数声明按照要求实现。在数据结构选型上直观的思路是采用std::set或std::map这类有序关联容器来存储乱序到达的子串及其索引。这两者的底层实现均为红黑树插入与查找操作的时间复杂度为O(log n)且每个节点需要额外存储父指针、颜色等信息内存开销显著。虽然这种方案在处理稀疏数据时足够灵活但对于大规模数据流场景性能瓶颈不容忽视。相比之下std::deque结合滑动窗口的设计更为高效它避免了std::vector在头部操作时频繁的数据搬移和内存重分配同时相较于红黑树结构std::deque的插入和随机访问均为O(1)常数时间且内存布局更加紧凑更适合处理高吞吐量的字节流重组任务。在这里主要给出std::deque的实现办方法以及对比std::deque和std::set两者在跑测试的时候耗时上的对比。在这里偏向选取std::deque是因为lab0在实现bytestream的时候也是选择的std::deque这样体现了一致性设计和逻辑对称的美感因为通过阅读handout可以明显感受到bytestream和这里缓冲滑动窗口在逻辑上其实是连续的参考capacity的图示数据从网络流动到应用程序其实更加自然。在数据结构的选取之中实验的handout存在以下一段提示这一段话直观的意思理解就是在实际接收substring缓冲区里面我们不能存储相互重叠的子字符串简单来说先接收到了2~4的字符此时又传过来了3~5的字符串我们不能存储两个而只需要在第一个字符串里面补充第二次新出现的字符即可。以下是我选取的数据结构ByteStream _output; //! The reassembled in-order byte stream size_t _capacity; //! The maximum number of bytes size_t _unassembled_start; //! The first index of the unassembed byte (beginning of the window) size_t _unassembled_size; //! The size of the unassembled bytes bool _eof; //! Whether the end of the stream has been reached size_t _eof_index; //! The index of the end of the stream std::dequechar _buffer; //! The buffer of sliding window std::dequebool _filled; //! Whether the buffer has been filled特别需要注意的是在实际的窗口滚动的时候我们都是遵循的左闭右开的规则比如_unassembled_start是第一个可以接受重组字符串的索引位置也就是说该位置当前没有字符在缓冲区可以放置后续传来的字符而_eof_index代表右侧的窗口末端这个位置是能接受的流末端的下一个字符这个索引位置被_capacity_限制是不能放置字符的。三、代码实现和测试下面是我stream_reassembler.hh的实现#include stream_reassembler.hh #include algorithm #include string // Dummy implementation of a stream reassembler. // For Lab 1, please replace with a real implementation that passes the // automated checks run by make check_lab1. // You will need to add private members to the class declaration in stream_reassembler.hh template typename... Targs void DUMMY_CODE(Targs ... /* unused */) {} using namespace std; StreamReassembler::StreamReassembler(const size_t capacity) : _output(capacity) , _capacity(capacity) , _unassembled_start(0) , _unassembled_size(0) , _eof(false) , _eof_index(0) , _buffer(capacity, \0) , _filled(capacity, false) {} //! \details This function accepts a substring (aka a segment) of bytes, //! possibly out-of-order, from the logical stream, and assembles any newly //! contiguous substrings and writes them into the output stream in order. void StreamReassembler::push_substring(const string data, const size_t index, const bool eof) { if (eof) { _eof true; _eof_index index data.size(); } if (_capacity 0) { if (_eof _unassembled_start _eof_index) _output.end_input(); return ; } const size_t first_unacceptable _unassembled_start _output.remaining_capacity(); const size_t data_end index data.size(); const size_t start max(index, _unassembled_start); const size_t end min(data_end, first_unacceptable); if (start end) { for (size_t pos start; pos end; pos) { const size_t offset pos % _capacity; if (!_filled[offset]) { _buffer[offset] data[pos - index]; _filled[offset] true; _unassembled_size; } } } string assembled; while (_filled[_unassembled_start % _capacity]) { const size_t offset _unassembled_start % _capacity; assembled.push_back(_buffer[offset]); _filled[offset] false; _unassembled_start; --_unassembled_size; } if (!assembled.empty()) _output.write(assembled); if (_eof _unassembled_start _eof_index) _output.end_input(); } size_t StreamReassembler::unassembled_bytes() const { return _unassembled_size; } bool StreamReassembler::empty() const { return _unassembled_size 0; }相关解释实际传输之中有可能最末端的substring先到而前半段还没有传输到位此时先到的应该先确定到缓冲区_buffer之中并且标记_eoftrue末端_eof_index也可以算出来if (eof) { _eof true; _eof_index index data.size(); }计算可接收窗口的参数const size_t first_unacceptable _unassembled_start _output.remaining_capacity();这里这么写比较直观实际上bytestream对象_output和streamReassembler的对象构造的时候的capacity是一样的二者的底层都是std::deque实际计算可接收区间公式为_first_unassembled_capcity-_output.size()这里把他简化了而已。求片段和窗口的交集需要下面的参数const size_t start max(index, _unassembled_start); const size_t end min(data_end, first_unacceptable);起点的位置应该是当前substring的索引和可接收位置更靠后的索引值终点位置应该是first_unacceptable和substring的末端更靠前的索引毕竟超过限制的部分是需要丢弃的。当第一个可接收位置被标记成为true的时候就可以开始考虑往bytestream里面写入了同时窗口可以开始在前端收缩。这里重组缓存区域可能其中会有几段区域都有连续重组数据整体窗口连不起来但只要存在连续的前缀就可以写入bytestrem并且向后移动窗口。只有 ByteStream 中的数据被上层读走接收窗口才会继续向后扩大体现了滑动窗口随着数据被消费而不断推进的思想。考虑用一个临时string类型变量将缓存之中的字符流变成连续的字符串这里考虑到lab0之中实现的bytestream真实的写入接口传递的也是string类型确保类型一致。最后只有确认收到了 EOF并且 EOF 之前的所有字节都已经连续组装完成才结束输出流。其实换一句话说收到 EOF 是一个事件EOF 前的数据全部组装完成才是转换条件最终的状态变化就是关闭bytestream想清楚这些问题其实也很容易理解代码的原理。测试结果如下可以看到全部的测试点其实都在半秒钟之内跑完了证明选取std::deque是一种效率比较高的选择。而使用std::set实际上速度就会稍微慢一点这篇博客给出了std::set的解决方案【计算机网络】Stanford CS144 Lab Assignments 学习笔记 - 康宇PL 。cmake命令默认构建的是release版本可以使用cmake .. -DCMAKE_BUILD_TYPEDebug进行显式的调试具体可以参考实验手册提供的调试方法。四、复盘通过 CS144 Lab 1我们可以对 TCP 接收端的数据重组机制有更加具体的认识。网络传输并不能保证数据报按顺序到达还可能出现丢失、重复和乱序因此接收端需要根据每段数据的索引将零散片段重新拼接成连续、有序的字节流并在确认下一个字节后尽快写入ByteStream。实现StreamReassembler的过程看似类似经典的区间合并问题实际上还要同时考虑重叠数据去重、容量限制和实时输出。例如两个片段部分重叠时重复字节不能被再次保存或计入unassembled_bytes()否则不仅统计结果会出错也会使capacity失去限制内存使用的意义。这里的容量同时约束已经写入但尚未读取的字节以及收到但尚未组装的字节因此程序必须根据当前可用空间裁剪新片段丢弃已经输出的旧数据和超出接收窗口的数据对TCP滑动窗口和容量管理的理解进一步加深。实验中最容易出错的是各种边界情况例如空字符串、完全重复、前后部分重叠、一个新区间覆盖多个旧区间以及前方缺口补齐后连续输出多个缓存片段。EOF 的处理同样需要严格的状态管理收到携带 EOF 的片段只代表已经知道整个流的结束位置并不表示可以立即关闭输出流只有 EOF 之前的全部字节都已经连续组装完成才能调用end_input()。在性能方面大规模随机测试要求实现不能反复扫描全部数据应借助合理的数据结构将主要处理过程控制在O(n)或O(n log n)范围内。整个实也可以体会到单元测试不仅是验证程序的工具还可以帮助理解需求通过分别分析有序、乱序、重叠、容量和 EOF 等测试场景能够逐步明确程序必须维持的不变量。总体来看Lab 1 不只是完成了一次字符串拼接任务更重要的是可以训练对于可靠传输、容量管理、区间算法、状态机、边界条件和测试驱动开发的综合理解。

相关新闻

C语言基础:函数

C语言基础:函数

2026/8/1 5:53:35

一段功能代码,被称为函数。为了避免代码的重复。 复用性。 开发不用从头开始(库函数)。模块化的思想 。 大问题,分解成小问题,逐个解决。设计函数 ,高内聚,低耦合。 功能越单一越好 ,对外部依赖越少越好。函…

[SECS/GEM研究] (五) SECS-II 是什么

[SECS/GEM研究] (五) SECS-II 是什么

2026/8/1 5:53:35

SECS/GEM 协议栈开发笔记 第 5 篇 基于代码库:Libsecs(一个 C 实现的 SEMI 协议栈) 说在前面:由于工作的原因,本人早些年开发了一套SEMI标准的协议栈用于公司的SECS标准实现,为了防止经验遗忘,…

Layerdivider完整指南:如何用AI技术实现智能图片分层

Layerdivider完整指南:如何用AI技术实现智能图片分层

2026/8/1 5:43:34

Layerdivider完整指南:如何用AI技术实现智能图片分层 【免费下载链接】layerdivider A tool to divide a single illustration into a layered structure. 项目地址: https://gitcode.com/gh_mirrors/la/layerdivider 在数字设计领域,设计师们经常…

C++引用与临时对象:深入理解生命周期延长与性能优化

C++引用与临时对象:深入理解生命周期延长与性能优化

2026/8/1 7:03:38

1. 项目概述:为什么我们还要深挖C引用?干了这么多年C,引用(Reference)这个语法糖,大家肯定都用得滚瓜烂熟了。不就是给变量起个别名嘛,初始化后不能改绑,用起来像指针但更安全。这几…

电感核心公式解析:从V=L*(di/dt)到工程选型实战

电感核心公式解析:从V=L*(di/dt)到工程选型实战

2026/8/1 7:03:38

1. 从“电感”到“电感公式”:一个被误解的起点在电子工程和电路设计的日常工作中,“电感”这个词几乎每天都会出现。无论是调试一个开关电源,还是分析一个射频电路的稳定性,我们总离不开它。然而,我发现一个有趣的现象…

fastjson 1245-jdk8u342 yakit测试

fastjson 1245-jdk8u342 yakit测试

2026/8/1 7:03:38

JDK8u191以后的JNDI就没那么轮椅了,得吃点操作 这周挺忙的,也是闲下来了打一打靶场 0x00 信息收集 重复操作就不一一列举了,看我往期文章。检查不在黑名单的类,858个 探测fastjson版本,1.2.45 探测能否出网&#x…

运维转型网安的五大核心技能与职业发展路径

运维转型网安的五大核心技能与职业发展路径

2026/8/1 7:03:38

1. 运维工程师转型网安的核心优势分析作为在IT基础设施领域摸爬滚打多年的运维老兵,转型网络安全领域有着天然的优势基础。运维人员日常接触的服务器、网络设备、系统架构等,恰恰构成了网络安全防护的第一道防线。我们积累的排障经验、系统优化技巧、日志…

Pixel手机解锁Bootloader与Root权限实现电信4G网络破解全攻略

Pixel手机解锁Bootloader与Root权限实现电信4G网络破解全攻略

2026/8/1 7:03:38

1. 项目概述与核心需求解析最近在折腾Pixel手机的朋友,尤其是想在国内用上电信4G网络的,估计都绕不开“破解”这个话题。我手头这台Pixel 6 Pro,原生系统对国内电信4G频段的支持总是不尽如人意,信号时有时无,网速也上不…

STM32F407 FSMC实战:驱动TFT屏与外部存储器的并行接口技术

STM32F407 FSMC实战:驱动TFT屏与外部存储器的并行接口技术

2026/8/1 6:53:37

1. 项目概述:为什么FSMC是STM32F407连接外部存储器的关键桥梁如果你用过STM32F103这类基础型号,想驱动一块大点的TFT屏或者接个SRAM、NOR Flash,大概率会被IO口模拟时序或者SPI的龟速折磨过。一旦项目升级到STM32F407这种带M4内核、主频168MH…

[具身智能-649]:个人电脑搭建 RTSP 服务完整方案(Windows / Ubuntu 双平台,适配 RDK X5 rtsp2display 调试)

[具身智能-649]:个人电脑搭建 RTSP 服务完整方案(Windows / Ubuntu 双平台,适配 RDK X5 rtsp2display 调试)

2026/7/30 9:53:22

目标:电脑作为RTSP 服务端,循环推送 H264/H265 视频流; RDK X5 通过 rtsp2display 拉流预览,完全不需要在开发板编译 live555。 提供两套成熟方案: ✅ 方案 A:FFmpeg(最简单,优先推…

PDF合并与动态水印的工程化方案:2026国内免费工具实测对比

PDF合并与动态水印的工程化方案:2026国内免费工具实测对比

2026/8/1 0:15:49

一、背景与测试方案 在实际项目交付中,PDF文件合并与版权保护水印的叠加是一个高频但容易被低估的技术需求。典型的处理链路涉及:多源PDF的文件流合并、页面级水印渲染(含透明度混合与图层叠加)、输出文件体积控制。看似简单的操作…

PDF拆分压完图糊了?2026国内免费实测,档案员都在用的组合方案

PDF拆分压完图糊了?2026国内免费实测,档案员都在用的组合方案

2026/8/1 4:47:48

说实话,提到PDF拆分再压缩,我真是被折腾得够呛。 上个月公司年度合同归档,一份300多页的PDF总合同,需要按年份拆分成三个独立文件,再分别压缩到10MB以内方便邮件发送各部门确认。我心想这还不简单?先找个海…

摆脱论文困扰!盘点2026年全网爆红的的AI论文写作工具

摆脱论文困扰!盘点2026年全网爆红的的AI论文写作工具

2026/8/1 0:03:03

一天写完毕业论文在2026年已不再是天方夜谭。2026年最炸裂、实测能大幅提速的AI论文写作工具,覆盖选题构思、文献整理、内容生成、格式排版等核心场景,真正帮你高效搞定论文难题。 一、全流程王者:一站式搞定论文全链路(一天定稿首…

导师推荐!2026最新AI论文工具测评与实用推荐

导师推荐!2026最新AI论文工具测评与实用推荐

2026/8/1 0:03:03

2026年真正好用的AI论文工具,核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测,千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队,覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。 一、…

告别游戏崩溃:XCOM 2模组管理器的智能革命

告别游戏崩溃:XCOM 2模组管理器的智能革命

2026/8/1 0:03:03

告别游戏崩溃:XCOM 2模组管理器的智能革命 【免费下载链接】xcom2-launcher The Alternative Mod Launcher (AML) is a replacement for the default game launchers from XCOM 2 and XCOM Chimera Squad. 项目地址: https://gitcode.com/gh_mirrors/xc/xcom2-lau…

摆脱论文困扰!盘点2026年全网爆红的的AI论文写作工具

摆脱论文困扰!盘点2026年全网爆红的的AI论文写作工具

2026/8/1 0:03:03

一天写完毕业论文在2026年已不再是天方夜谭。2026年最炸裂、实测能大幅提速的AI论文写作工具,覆盖选题构思、文献整理、内容生成、格式排版等核心场景,真正帮你高效搞定论文难题。 一、全流程王者:一站式搞定论文全链路(一天定稿首…

导师推荐!2026最新AI论文工具测评与实用推荐

导师推荐!2026最新AI论文工具测评与实用推荐

2026/8/1 0:03:03

2026年真正好用的AI论文工具,核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测,千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队,覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。 一、…

告别游戏崩溃:XCOM 2模组管理器的智能革命

告别游戏崩溃:XCOM 2模组管理器的智能革命

2026/8/1 0:03:03

告别游戏崩溃:XCOM 2模组管理器的智能革命 【免费下载链接】xcom2-launcher The Alternative Mod Launcher (AML) is a replacement for the default game launchers from XCOM 2 and XCOM Chimera Squad. 项目地址: https://gitcode.com/gh_mirrors/xc/xcom2-lau…