【斯坦福CS144】Lab2
一、实验目的
实现一个 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;
}
原文地址:https://blog.csdn.net/qq_37293468/article/details/142762905
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!