首页 > 其他分享 >CS144-Lab1-StreamReassembler

CS144-Lab1-StreamReassembler

时间:2023-01-24 00:11:24浏览次数:57  
标签:index StreamReassembler data CS144 seg Lab1 size segment left

lab 地址 :lab1-doc
代码实现:lab1-code

1. 目标

TCP 一个很重要的特性是可以实现顺序、无差错、不重复和无报文丢失的流传输。在 lab0 中我们已经实现了一个字节流 ByteStream,而在 lab1 我们需要保证传入 ByteStream 的字节流是有序可靠不重复的,在此之上需要封装实现一个 StreamReassembler
为了确定每次 push 进来的字节流的顺序,每个字节流都有一个 index,如果完整字符串为:
“abcdefg”,然后拆分成 abcbcdefg 三个子串,则他们的 index 分别为 0,1,5,也就是首字符在 完整字节流中的位置,index 从 0 开始,参考下图:

image

StreamReassembler 需要做到去重,比如 abcbcd 两个子串重合了 bc 部分,那么需要合并,最终的字符串为 abcd。

2. 实现

StreamReassembler 的核心接口只有一个:

//! \brief Receive a substring and write any newly contiguous bytes into the stream.
//!
//! The StreamReassembler will stay within the memory limits of the `capacity`.
//! Bytes that would exceed the capacity are silently discarded.
//!
//! \param data the substring
//! \param index indicates the index (place in sequence) of the first byte in `data`
//! \param eof the last byte of `data` will be the last byte in the entire stream
void push_substring(const std::string &data, const uint64_t index, const bool eof);

由于字节流可能为乱序 push,因此需要缓存还不能 push 到 ByteStream 的 string
大致流程如下:

  1. 检查是否为预期的字节流(维护一个当前预期接受的 _assemble_idx ,只有传入的 string 的 index > _assemble_idx 时,才为预期的字节流)
  2. 如果为预期字节流,直接压入 ByteStream,更新 _assemble_idx,合并缓存中满足合并条件的 string
  3. 如果不是预期的字节流,则缓存起来,并且检查能否和缓存的字符串合并

code 如下(还能再简洁很多),完整 code 参考 (lab1-code):

void StreamReassembler::push_substring(const string &data, const size_t index, const bool eof) {
	if (eof) {
		_eof_idx = data.size() + index;
	}
	
	// not expect segement, cache it
	if (index > _assemble_idx) {
		_merge_segment(index, data);
		return;
	}
	
	// expect segment, write it to ByteStream
	int start_pos = _assemble_idx - index;
	int write_cnt = data.size() - start_pos;
	// not enough space
	if (write_cnt < 0) {
		return;
	}
	
	_assemble_idx += _output.write(data.substr(start_pos, write_cnt));
	// search the next segment
	std::vector<size_t> pop_list;
	for (auto segment : _segments) {
	// already process or empty string
		if (segment.first + segment.second.size() <= _assemble_idx || segment.second.size() == 0) {
			pop_list.push_back(segment.first);
			continue;
		}
		// not yet
		if (_assemble_idx < segment.first) {
			continue;
		}
		start_pos = _assemble_idx - segment.first;
		write_cnt = segment.second.size() - start_pos;
		_assemble_idx += _output.write(segment.second.substr(start_pos, write_cnt));
		pop_list.push_back(segment.first);
	}
	// remove the useless segment
	for (auto segment_id : pop_list) {
		_segments.erase(segment_id);
	}
	
	if (empty() && _assemble_idx == _eof_idx) {
		_output.end_input();
	}
}

正常情况下符合预期的字节流我们可以直接 push 进 ByteStream,如果有重叠部分则从重叠部分后面开始 push,理论上只有这两种情况( 符合预期 这个前提剔除掉了麻烦的情况):

image

这里麻烦点主要在于,对于不符合预期的字符串,我们要缓存起来,并且合并缓存中的字符串,这里主要梳理好有几种情况即可,主要有如下情况:
缓存字符串在目标字符串左侧的

image

缓存字符串在目标字符串右侧的

image

code 如下:

void StreamReassembler::_merge_segment(size_t index, const std::string& data) {
	size_t data_left = index;
	size_t data_right = index + data.size();
	std::string data_copy = data;
	std::vector<size_t> remove_list;
	bool should_cache = true;
	
	for (auto segment : _segments)
	{
		size_t seg_left = segment.first;
		size_t seg_right = segment.first + segment.second.size();
		//|new_index |segment.first |segment.second.size() |merge_segment.size
		if (data_left <= seg_left && data_right >= seg_left) {
			if (data_right >= seg_right) {
				remove_list.push_back(segment.first);
				continue;
			}
		
			if (data_right < seg_right) {
				data_copy = data_copy.substr(0, seg_left - data_left) + segment.second;
				data_right = data_left + data_copy.size();
				remove_list.push_back(segment.first);
			}
		}
		
		if (data_left > seg_left && data_left <= seg_right) {
			if (data_right <= seg_right) {
				should_cache = false;
			}
	
			if (data_right > seg_right) {
				data_copy = segment.second.substr(0, data_left - seg_left) + data_copy;
				data_left = seg_left;
				data_right = data_left + data_copy.size();
				remove_list.push_back(segment.first);
			}
		}
	}
	
	// remove overlap data
	for (auto remove_idx : remove_list) {
		_segments.erase(remove_idx);
	}
	
	if (should_cache)
		_segments[data_left] = data_copy;
	}
}

3. 测试

image

标签:index,StreamReassembler,data,CS144,seg,Lab1,size,segment,left
From: https://www.cnblogs.com/lawliet12/p/17065710.html

相关文章

  • CS144-Lab0-networking warmup
    lab地址:lab0-doc代码实现:lab0-code1.目标利用官方支持的TCPSocket,实现一个wget功能,其次,实现一个可靠的字节流。2.实现2.1webget实现上比较简单,主要就是:......
  • CS144-lab6-the IP router
    lab地址:lab6-doc代码实现:lab6-code1.目标lab6主要要实现一个路由的机制,首先互联网由多个局域网组成(不太严谨的说法),在lab5中我们只能支持在单个局域网中传递消......
  • LAB1 VRRP实验
    ■实验拓扑■实验需求1.多厂商的网关冗余(VRPP)2.考虑上行/上上行/下行链路的之间的track3.生成树配置4.VPC能访问R4的loopback口地址(8.8.8.8)■实验步骤▶思科路由器CISCO......
  • Ucore_lab1 相关
    https://kiprey.github.io/2020/08/uCore-1/学堂在线清华大学的Ucore实验指导书以及在线视频第一点是一个博客,很优秀的文章,包含了很多内容,借以引用。再在此基础上写点......
  • 2022-6.824-Lab1:Map&Reduce
    lab地址:https://pdos.csail.mit.edu/6.824/labs/lab-mr.html1.介绍准备工作阅读MapReduce做什么实现一个分布式的Map-Reduce结构,在原先的代码结构中6.......
  • CS144 lab1: stitching substrings into a byte stream
    CS144lab1:stitchingsubstringsintoabytestream​ Lab1中我们主要实现一个叫做StreamReassembler的东西。从Lab1提供的文档中,我们可以大致了解未来我们将要自己实......
  • cmu15445_lab1_BUFFER POOL
    BufferPoolManager整理一下cmu15445的实验的实现内容,具体实验的代码写的太丑就不公开了。Pagepage:page是一个数据库中存储的最小单位,也是磁盘和内存交换的最小单位,每......
  • 6.824 lab1-MapReduce
    lab1是实现MapReduce老师完成了框架的大部分我我们只需要做的是填充哪重要的几个部分2022的官方连接https://pdos.csail.mit.edu/6.824/labs/lab-mr.html准备工作下......
  • 恶意代码分析实战 恶意代码的网络特征 lab14-1 14-2 14-3 都是http c2,并用到了自定义
       先反编译看看:函数在做base64加密:   验证下想法,果然:后面的功能,就是在下载执行了:   我们分析下细节: 问题1:使用wireshark进行监控网络特征,运......
  • 【CS144】Spongeの类图分析(lab0~lab4)
    lab4写不下去了,感觉对代码理不清了,打算重新整理一下。重点是五个类,(正好对应lab0~lab4)ByteStream类这里只展示startcode中类的模样(具体的实现可能各有不同,所以重点看函......