【斯坦福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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Robbi_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值