【斯坦福CS144】Lab2

news/2024/10/9 20:25:36/

一、实验目的

实现一个 TCPReceiver,用以接收传入的 TCP segment 并将其转换成用户可读的数据流。

二、实验内容

1.接收TCP segment;

2.重新组装字节流(包括EOF);

3.确定应该发回给发送者的信号,以进行数据确认和流量控制。

三、实验过程

输入git merge origin/check2-startercode 获取Lab2

用文本编辑器打开./src/wrapping_integers.hh

修改代码,代码分析见注释

用文本编辑器打开./src/wrapping_integers.cc

修改代码,代码分析见注释

在build目录下输入make编译可执行文件

输入make check2测试程序

发现转换测试全部通过,但TCP接收测试失败,需要修改TCP接收的源码。用文本编辑器打开./src/tcp_receiver.hh

修改代码

用文本编辑器打开./src/tcp_receiver.cc

修改代码

重新在build目录下输入make编译可执行文件

再次输入make check2进行测试

发现全部通过

实验结束

四、实验体会

1.本实验中,TCPReceiver 除了将读入的数据写入至 ByteStream 中以外,它还需要告诉发送者两个属性:

第一个未组装的字节索引,称为确认号ackno,它是接收者需要的第一个字节的索引。

第一个未组装的字节索引和第一个不可接受的字节索引之间的距离,称为 窗口长度window size。

ackno 和 window size 共同描述了接收者当前的接收窗口。接收窗口是 发送者允许发送数据的一个范围,通常 TCP 接收方使用接收窗口来进行流量控制,限制发送方发送数据。

2.下图是CS144 对 TCP receiver 的期望执行流程:

三次握手:

3.本部分需要注意结合前一个lab流重组器进行理解,如果字节流未按序到达,那么bytes_written()返回的还是按序到达的最后一个字节的序号。

五、代码附录

wrapping_integers.hh

#pragma once#include <cstdint>/** Wrap32 类型表示一个32位无符号整数,具有以下特性:*    - 从任意“零点”(初始值)开始。*    - 当它达到 2^32 - 1 时会回到零点。*/class Wrap32
{
protected:uint32_t raw_value_ {}; // 存储32位无符号整数的值public:explicit Wrap32( uint32_t raw_value ) : raw_value_( raw_value ) {} // 构造函数,给定一个无符号32位整数作为参数/* 根据绝对序列号 n 和零点构造一个 Wrap32 对象。*/static Wrap32 wrap( uint64_t n, Wrap32 zero_point );/** unwrap 方法返回一个绝对序列号,它回到这个 Wrap32 对象,给定零点和一个“检查点”:* 一个接近期望答案的绝对序列号。** 有许多可能的绝对序列号,它们都会回到同一个 Wrap32 对象。* unwrap 方法应该返回最接近检查点的那个序列号。*/uint64_t unwrap( Wrap32 zero_point, uint64_t checkpoint ) const;// 重载加法运算符,用于增加一个无符号32位整数Wrap32 operator+( uint32_t n ) const { return Wrap32 { raw_value_ + n }; }// 重载相等运算符,用于比较两个 Wrap32 对象是否相等bool operator==( const Wrap32& other ) const { return raw_value_ == other.raw_value_; }// 获取原始值uint32_t get_raw_value() const {return raw_value_;}
};

wrapping_integers.cc

#include "wrapping_integers.hh"
//#include<algorithm>
using namespace std;Wrap32 Wrap32::wrap( uint64_t n, Wrap32 zero_point )
{// Your code here.//(void)n;//(void)zero_point;//uint32_t raw_value = zero_point + static_cast<uint32_t>n;return (zero_point + static_cast<uint32_t>(n));
}uint64_t Wrap32::unwrap( Wrap32 zero_point, uint64_t checkpoint ) const
{// Your code here.//(void)zero_point;//(void)checkpoint; //uint64_t all_1=0x 0000 0000 FFFF FFFF;//uint64_t num = checkpoint/(static<uint64_t>all_1);//Wrap32 wrap_checkpoint = wrap(checkpoint, zero_point);uint64_t num = checkpoint >> 32;//uint64_t absolute_seqno=0;//uint32_t all_1=0xFFFFFFFF;uint32_t zero2raw_distance = this->get_raw_value() - zero_point.get_raw_value() ;//zero2raw_distance = static_cast<uint64_t> (zero2raw_distance);//转换为64之后,在checkpoint附近有三个长度为2^32的段,每个段都有一个点,我把这三个点都检查一遍,看哪个点的距离最近uint64_t ans2=(num<<32) + zero2raw_distance;uint64_t distance2;if(ans2>=checkpoint)distance2 = ans2-checkpoint;else distance2 = checkpoint - ans2;//这里要判断一下num能不能减一uint64_t ans1=((num-1)<<32) + zero2raw_distance;if(num==0) ans1=ans2;uint64_t distance1 = checkpoint - ans1;uint64_t ans3=((num+1)<<32) + zero2raw_distance;uint64_t distance3 = ans3 - checkpoint;uint64_t mindis ;//= min(distance1, min(distance2, distance3));mindis = distance2>distance3? distance3:distance2;mindis = mindis>distance1? distance1:mindis;if(mindis==distance1)return ans1;else if(mindis==distance2)return ans2;else  return ans3;
}

tcp_receiver.hh

#pragma once#include "reassembler.hh"
#include "tcp_receiver_message.hh"
#include "tcp_sender_message.hh"class TCPReceiver
{private:bool receive_syn{false};Wrap32 SYN_seqno{0};
public:/** The TCPReceiver receives TCPSenderMessages, inserting their payload into the Reassembler* at the correct stream index.*/void receive( TCPSenderMessage message, Reassembler& reassembler, Writer& inbound_stream );/* The TCPReceiver sends TCPReceiverMessages back to the TCPSender. */TCPReceiverMessage send( const Writer& inbound_stream ) const;
};

tcp_receiver.cc

#include "tcp_receiver.hh"
#include<optional>
using namespace std;void TCPReceiver::receive( TCPSenderMessage message, Reassembler& reassembler, Writer& inbound_stream )
{// Your code here.//(void)message;//(void)reassembler;//(void)inbound_stream;if(receive_syn==false&&message.SYN==false)return;//没有syn直接返回if(message.SYN){SYN_seqno = message.seqno;message.seqno = message.seqno + 1;//去掉syn位receive_syn=true;}uint64_t stream_index = message.seqno.unwrap(SYN_seqno, inbound_stream.bytes_pushed()+1) - 1;reassembler.insert(stream_index, message.payload.release(), message.FIN, inbound_stream);return;
}TCPReceiverMessage TCPReceiver::send( const Writer& inbound_stream ) const
{// Your code here.//(void)inbound_stream;//uint64_t ack_stream_index = inbound_stream.bytes_pushed() + 1;//uint64_t ack_absolute_seqno = ack_stream_index + 1;TCPReceiverMessage sendmessage{};sendmessage.window_size = inbound_stream.available_capacity()>UINT16_MAX? UINT16_MAX:inbound_stream.available_capacity();//if(sendmessage.window_size>=UINT16_MAX) sendmessage.window_size=UINT16_MAX;if(receive_syn==false)return sendmessage;else{uint64_t ack_absolute_seqno = inbound_stream.bytes_pushed() + 1 + inbound_stream.is_closed();Wrap32 ackno = Wrap32::wrap(ack_absolute_seqno, SYN_seqno);sendmessage.ackno.emplace(ackno);}return sendmessage;
}

http://www.ppmy.cn/news/1536806.html

相关文章

UE4 材质学习笔记03(翻书(Flipbook)动画/环境混合)

一.FlipBook Animation 如果你想让游戏以每秒30帧的速度运行&#xff0c;所有内容都必须在33毫秒内渲染出来&#xff0c; 如果你想让游戏以每秒60帧的速度运行的话&#xff0c;必须在16毫秒内。 所以当一个效果需要很多细节的时候&#xff0c;往往会离线创建它&#xff0c;然…

Linux操作系统——概念扫盲I

目录 虚拟机概念刨析 在那之前&#xff0c;询问什么是虚拟化&#xff1f; 现在来看看什么是虚拟机 虚拟机有啥好的 小差&#xff1a;那JVM也叫Java Virtual Machine&#xff0c;有啥区别呢&#xff1f; Reference 虚拟机概念刨析 我们下面来简单聊聊虚拟机这个概念。对于…

基于springboot vue 学生就业信息管理系统设计与实现

博主介绍&#xff1a;专注于Java&#xff08;springboot ssm springcloud等开发框架&#xff09; vue .net php phython node.js uniapp小程序 等诸多技术领域和毕业项目实战、企业信息化系统建设&#xff0c;从业十五余年开发设计教学工作☆☆☆ 精彩专栏推荐订阅☆☆☆☆…

UE5.4.3 录屏回放系统ReplaySystem蓝图版

这是ReplaySystem的蓝图使用方法版&#xff0c;以第三人称模版为例&#xff0c;需要几个必须步骤 项目config内DefaultEngine.ini的最后添加&#xff1a; [/Script/Engine.GameEngine] NetDriverDefinitions(DefName"DemoNetDriver",DriverClassName"/Script/…

Qt 中的 QChartView

深入理解 Qt 的 QChartView&#xff1a;图表展示与交互 QChartView 是 Qt Charts 模块中的一个核心类&#xff0c;它用于在 Qt 应用程序中显示图表&#xff0c;并支持多种用户交互方式。它继承自 QGraphicsView&#xff0c;通过封装 QChart&#xff0c;为用户提供了强大的图表…

Oracle中处理空值函数(NVL、NVL2、NULLIF等)详解

文章目录 前言一、函数语法NVL函数NVL2函数NULLIF函数COALESCE函数DECODE函数 二、用法区别三、测试用例总结 前言 本文将介绍Oracle中处理空值的函数。常用的处理函数有&#xff1a;NVL()、NVL2()、NULLIF()、COALESCE()。此外DECODE()和CASE()函数也可以起到处理空值的效果。…

日记学习小迪安全27

感觉复制粘贴没有意思&#xff0c;而且还有点浪费时间&#xff0c;主要是学习&#xff0c;不是复制&#xff0c;那就复制别人的吧 第27关就参考这篇文章吧&#xff0c;以下大部分内容都是参考以下文章&#xff08;侵权删除&#xff09; 第27天&#xff1a;WEB攻防-通用漏洞&a…

虚拟化数据恢复—互斥不当导致vmfs卷损坏的数据恢复案例

虚拟化数据恢复环境&#xff1a; 某企业信息管理平台&#xff0c; 几台VMware ESX Server主机共享一台存储设备&#xff0c;大约有几十台虚拟机。 虚拟化故障&原因&#xff1a; Vcenter报告虚拟磁盘丢失。管理员通过ssh远程到ESX中执行fdisk -l命令查看磁盘&#xff0c;发…