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:54:06阅读更多 →
[SECS/GEM研究] (五) SECS-II 是什么

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

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

2026/8/1 5:54:06阅读更多 →
【微调】大模型微调(Fine-tuning)

【微调】大模型微调(Fine-tuning)

第一部分:概述 大模型微调(Fine-tuning),在什么业务场景下需要微调而不是直接使用基础模型? 1. 从“通才”到“专才” 可以把基础大模型(如GPT-4、Llama)看作一位接受了通识教育(海量互联网文本&#xff09…

2026/8/1 5:54:06阅读更多 →
Chrome浏览器localhost:6667无法访问?解析ERR_UNSAFE_PORT与端口安全策略

Chrome浏览器localhost:6667无法访问?解析ERR_UNSAFE_PORT与端口安全策略

1. 问题现场:当localhost:6667在Chrome中“消失”如果你是一名开发者,或者经常需要在本机搭建测试环境,那么对http://localhost:8080或http://127.0.0.1:3000这样的地址一定不会陌生。localhost代表本机回环地址,是我们进行本地开…

2026/8/1 7:08:34阅读更多 →
Starrocks 4.0.2索引技术解析与性能优化实践

Starrocks 4.0.2索引技术解析与性能优化实践

1. Starrocks 4.0.2索引技术全景解析Starrocks作为新一代MPP分析型数据库,在4.0.2版本中对索引系统进行了重要升级。与传统数据库的B树索引不同,Starrocks采用了更适合OLAP场景的混合索引架构。在实际测试中,一个包含1亿条数据的表使用N-gram…

2026/8/1 7:08:34阅读更多 →
【AI物流降本增效实战指南】:20年行业专家亲授5大落地场景+3个避坑红线

【AI物流降本增效实战指南】:20年行业专家亲授5大落地场景+3个避坑红线

更多请点击: https://kaifayun.com 第一章:AI物流降本增效的底层逻辑与价值锚点 AI在物流领域的价值并非源于算法本身的复杂性,而在于其对“不确定性”的系统性消解能力。传统物流依赖经验决策与静态规则,在需求波动、运力错配、…

2026/8/1 7:08:34阅读更多 →
网站病毒清除怎么做?公司网站维护与网站木马解决全流程方案,公司网站被病毒入侵、被挂木马?专业网站病毒清除+公司网站维护+

网站病毒清除怎么做?公司网站维护与网站木马解决全流程方案,公司网站被病毒入侵、被挂木马?专业网站病毒清除+公司网站维护+

网站病毒清除怎么做?公司网站维护与网站木马解决全流程方案“公司网站突然跳转到博彩页面”、“网站文件被加密勒索”、“服务器里多了好多不认识的文件”——这些是网站病毒入侵后的典型症状。对于企业而言,网站不仅是品牌展示的窗口,更是业…

2026/8/1 7:08:34阅读更多 →
AI摆摊:在 muShanghai × 观猹 AI 练摊集市的一次高密度体验

AI摆摊:在 muShanghai × 观猹 AI 练摊集市的一次高密度体验

AI摆摊:在 muShanghai 观猹 AI 练摊集市的一次高密度体验 那天下午,我拖着行李箱站在上海静安寺附近一个不起眼的弄堂口,里面传来此起彼伏的键盘敲击声和机器人关节电机转动的声音。门口挂着一块手写牌:「muShanghai 观猹 AI 练…

2026/8/1 7:08:34阅读更多 →
Python脚本在cmd中无输出?系统化排查与解决方案

Python脚本在cmd中无输出?系统化排查与解决方案

1. 问题现象与初步排查如果你在Windows的cmd命令行里,输入python3 your_script.py后,光标闪了一下,然后什么也没发生——没有输出,没有报错,程序也没运行,cmd只是安静地回到了命令提示符状态——那你大概率…

2026/8/1 7:06:34阅读更多 →
覆盖国产 + 海外 + 开源模型,OpenClaw 2.7.9 Windows/Mac 双端部署详解

覆盖国产 + 海外 + 开源模型,OpenClaw 2.7.9 Windows/Mac 双端部署详解

🔹 工具基础介绍 OpenClaw 是开源生态中一款实用性较强的本地智能工具,凭借本地离线运行、可视化图形操作和任务自动化三大核心特性,赢得了众多用户的青睐。与普通在线对话AI工具不同,它属于能够直接操控本机软硬件的智能数字员工…

2026/7/31 20:44:05阅读更多 →
伺服阀焊完微漏毁整机?精密激光焊接三关锁住高压

伺服阀焊完微漏毁整机?精密激光焊接三关锁住高压

所谓液压伺服阀体的精密激光焊接,是用激光束对阀座壳体(通常为不锈钢或铝合金)进行密封焊接,使阀体在21-35MPa的高压液压油或压缩气体中长期运行而不发生介质泄漏。液压伺服阀是高端液压系统的"大脑"。从航空航天飞行控…

2026/7/31 17:41:43阅读更多 →
D2DX:三步实现《暗黑破坏神2》高清宽屏体验的终极指南

D2DX:三步实现《暗黑破坏神2》高清宽屏体验的终极指南

D2DX:三步实现《暗黑破坏神2》高清宽屏体验的终极指南 【免费下载链接】d2dx D2DX is a complete solution to make Diablo II run well on modern PCs, with high fps and better resolutions. 项目地址: https://gitcode.com/gh_mirrors/d2/d2dx 你是否还在…

2026/7/31 20:44:05阅读更多 →
无损视频剪辑终极指南:如何实现快速高效的多媒体处理

无损视频剪辑终极指南:如何实现快速高效的多媒体处理

无损视频剪辑终极指南:如何实现快速高效的多媒体处理 【免费下载链接】lossless-cut The swiss army knife of lossless video/audio editing 项目地址: https://gitcode.com/gh_mirrors/lo/lossless-cut 在数字媒体创作领域,视频编辑处理的质量损…

2026/8/1 0:00:10阅读更多 →
AI辅助本科论文写作:8大工具评测与高效使用指南

AI辅助本科论文写作:8大工具评测与高效使用指南

1. 本科生论文写作的AI辅助现状本科毕业论文是每个大学生必须跨越的一道坎。记得我当年写论文时,光是文献检索就花了整整两周时间,打印的参考文献堆满了半个书桌。如今AI技术的发展为学术写作带来了革命性变化,合理使用这些工具可以节省80%以…

2026/8/1 0:00:10阅读更多 →
如何快速配置大麦自动抢票系统:从零开始搭建Python抢票助手

如何快速配置大麦自动抢票系统:从零开始搭建Python抢票助手

如何快速配置大麦自动抢票系统:从零开始搭建Python抢票助手 【免费下载链接】ticket-purchase 大麦自动抢票,支持人员、城市、日期场次、价格选择 项目地址: https://gitcode.com/GitHub_Trending/ti/ticket-purchase 还在为抢不到热门演唱会门票…

2026/8/1 0:00:10阅读更多 →
无损视频剪辑终极指南:如何实现快速高效的多媒体处理

无损视频剪辑终极指南:如何实现快速高效的多媒体处理

无损视频剪辑终极指南:如何实现快速高效的多媒体处理 【免费下载链接】lossless-cut The swiss army knife of lossless video/audio editing 项目地址: https://gitcode.com/gh_mirrors/lo/lossless-cut 在数字媒体创作领域,视频编辑处理的质量损…

2026/8/1 0:00:10阅读更多 →
AI辅助本科论文写作:8大工具评测与高效使用指南

AI辅助本科论文写作:8大工具评测与高效使用指南

1. 本科生论文写作的AI辅助现状本科毕业论文是每个大学生必须跨越的一道坎。记得我当年写论文时,光是文献检索就花了整整两周时间,打印的参考文献堆满了半个书桌。如今AI技术的发展为学术写作带来了革命性变化,合理使用这些工具可以节省80%以…

2026/8/1 0:00:10阅读更多 →
如何快速配置大麦自动抢票系统:从零开始搭建Python抢票助手

如何快速配置大麦自动抢票系统:从零开始搭建Python抢票助手

如何快速配置大麦自动抢票系统:从零开始搭建Python抢票助手 【免费下载链接】ticket-purchase 大麦自动抢票,支持人员、城市、日期场次、价格选择 项目地址: https://gitcode.com/GitHub_Trending/ti/ticket-purchase 还在为抢不到热门演唱会门票…

2026/8/1 0:00:10阅读更多 →