【斯坦福计网CS144项目】Lab2 实现一个简单的 TCP 接收类

🕺作者: 主页

我的专栏
C语言从0到1
探秘C++
数据结构从0到1
探秘Linux

😘欢迎关注:👍点赞🙌收藏✍️留言

🏇码字不易,你的👍点赞🙌收藏❤️关注对我真的很重要,有问题可在评论区提出,感谢支持!!!

文章目录

  • 一、实验目的
  • 二、实验说明
  • 三、实验内容
  • 四、实验体会
  • 五、代码附录

一、实验目的

1 实现一个简单的 TCP 接收类
2 对 TCP 数据传输有更深的理解

二、实验说明

  1. 我们在lab0中实现了字节流(ByteStream)的流控制抽象化。随后,在lab1中,我们创建了一个名为StreamReassembler的结构体,它可以接收同一字节流的子字符串序列,并将它们重新组装到原始流中。

  2. 尽管这些模块已经能够满足实验要求,但它们并没有涵盖TCP传输控制协议的细节。因此,在lab2中,我们打算实现一个名为TCPReceiver的模块,其主要功能是处理传入字节流的数据。换句话说,它能够正确读取IP数据报中所携带的信息。

  3. TCPReceiver将具备以下能力:对于正确接收且按序到达的数据报,它能够向发送方发送确认号,发送方可以根据此确认号来调整自身的发送行为。此外,TCPReceiver还能够告知发送方自身的接收窗口大小,以便发送方相应地进行发送调整。

三、实验内容

  1. 拉取lab2的代码,合并到当前目录中,然后在build目录下输入“make”对代码进行编译,结果无误开始下一步编写代码。
  2. 这次实验需要编写的文件如下图3-1所示。

image.png
图3-1 需要编写的文件

  1. 使用vscode远程连接虚拟机,可以很方便的编写代码,下面都是在vscode编辑器下进行。
  2. 实现在64位索引和32位序列号之间转换,编写"wrapping_integers.cc""wrapping_integers.hh"文件如图3-2、3-3所示。源代码见附录。

image.png
图 3-2 wrapping_integers.cc
image.png
图 3-3 wrapping_integers.hh

  1. 实现TCP接收器,编写tcp_receiver.cc tcp_receiver.hh文件如图3-4、3-5所示。源代码见附录。

image.png
图 3-4 tcp_receiver.cc
image.png
图3-5 tcp_receiver.hh

  1. 在build 目录下输入命令"make check2" 对lab2进行检查,结果如3-6所示,可以看到所有的测试样例全部通过。

image.png
图3-6 测试结果

四、实验体会

在本次实验中,我们实现了一个简单的TCP接收类。通过这个实验,我对TCP数据传输有了更深的理解,并学会了如何处理传入字节流的数据。
在实验过程中,我们创建了几个关键的模块来实现TCP接收类的功能。首先,在lab0中,我们实现了字节流的流控制抽象化,以便后续的操作。然后,在lab1中,我们创建了一个名为StreamReassembler的结构体,它可以接收同一字节流的子字符串序列,并将它们重新组装到原始流中。虽然这些模块已经能够满足实验要求,但它们并没有涵盖TCP传输控制协议的细节。
因此,在lab2中,我们打算实现一个名为TCPReceiver的模块,它的主要功能是处理传入字节流的数据。具体而言,TCPReceiver具备以下能力:

  1. 对于正确接收且按序到达的数据报,它能够向发送方发送确认号,发送方可以根据此确认号来调整自身的发送行为。
  2. TCPReceiver还能够告知发送方自身的接收窗口大小,以便发送方相应地进行发送调整。

在实现TCPReceiver模块的过程中,我们使用了Wrap32类来处理32位无符号整数的包装和解包装操作。Wrap32类具有一个起始值(zero point),当整数达到2^32 - 1时会重新回到起始值,实现循环计数的功能。
通过实现TCPReceiver模块,我们可以根据接收到的数据报的序列号(seqno)来处理数据,并将其插入到Reassembler中的正确流索引位置。同时,我们还可以根据已经接收到的数据量来确定应该发送的确认号(ackno)以及接收窗口大小(window size)。
总的来说,通过完成这个实验,我对TCP数据传输有了更深入的理解,特别是在处理接收端的数据时。我学会了如何使用TCPReceiver来处理传入字节流,并与发送方进行正确的数据交互。这个实验提供了一个很好的实践机会,使我更加熟悉TCP协议的工作原理和相关概念。

五、代码附录

  1. wrapping_integers.hh
#pragma once

#include <cstdint>

/*
 * The Wrap32 type represents a 32-bit unsigned integer that:
 *    - starts at an arbitrary "zero point" (initial value), and
 *    - wraps back to zero when it reaches 2^32 - 1.
 */

class Wrap32
{
protected:
  uint32_t raw_value_ {};

public:
  explicit Wrap32( uint32_t raw_value ) : raw_value_( raw_value ) {}

  /* Construct a Wrap32 given an absolute sequence number n and the zero point. */
  static Wrap32 wrap( uint64_t n, Wrap32 zero_point );

  /*
   * The unwrap method returns an absolute sequence number that wraps to this Wrap32, given the zero point
   * and a "checkpoint": another absolute sequence number near the desired answer.
   *
   * There are many possible absolute sequence numbers that all wrap to the same Wrap32.
   * The unwrap method should return the one that is closest to the checkpoint.
   */
  uint64_t unwrap( Wrap32 zero_point, uint64_t checkpoint ) const;

  Wrap32 operator+( uint32_t n ) const { return Wrap32 { raw_value_ + n }; }
  bool operator==( const Wrap32& other ) const { return raw_value_ == other.raw_value_; }
};
  1. wrapping_integers.cc
#include "wrapping_integers.hh"

using namespace std;


Wrap32 Wrap32::wrap( uint64_t n, Wrap32 zero_point )
{
  // Your code here.
  // 当模是进制数的倍数时,取模就等效与截断,例如十进制:123 % 100,直接截断前面,保留最后两位得到23
  // 因此这里uint64_t n直接强转成uint32_t,截断前面32位,只保留低32位,等效于%2^32
  Wrap32 seqno( zero_point + static_cast<uint32_t>( n ) );
  (void)n;
  (void)zero_point;
  return seqno;
}
// seqno -> absolute seqno
uint64_t Wrap32::unwrap( Wrap32 zero_point, uint64_t checkpoint ) const
{
  // Your code here.
  uint64_t abs_seqno = static_cast<uint64_t>( this->raw_value_ - zero_point.raw_value_ );
  // 现在的abs_seqno是mod之后的值,还需要把它还原回mod之前的
  // 由于还原之后的abs_seqno需要离checkpoint最近,因此先找出checkpoint前后的两个可还原的abs_seqno,那个近选哪个就好
  // checkpoint / 2^32得到商,也即mod 2^32的次数
  uint64_t times_mod = checkpoint >> 32; // >>32等价于除以2^32
  // mod 2^32的余数,<<32实现截断前面32位,>>32实现保留低32位
  uint64_t remain = checkpoint << 32 >> 32; // 总体等效于%2^32,
  uint64_t bound;
  // 先取得离checkpoint最近的边界的mod次数(times_mod是左边界mod次数)
  if ( remain < 1UL << 31 ) // remain属于[0,2^32-1],mid=2^31(即1UL << 31)
    bound = times_mod;
  else
    bound = times_mod + 1;
  // 以该边界的左右边界作为base,还原出2个mod之前的abs_seqno值
  // <<32等价于乘上2^32
  uint64_t abs_seqno_l = abs_seqno + ( ( bound == 0 ? 0 : bound - 1 ) << 32 ); // 注意bound=0的特殊情况
  uint64_t abs_seqno_r = abs_seqno + ( bound << 32 );
  // 判断checkpoint离哪个abs_seqno值近就取那个
  if ( checkpoint < ( abs_seqno_l + abs_seqno_r ) / 2 )
    abs_seqno = abs_seqno_l;
  else
    abs_seqno = abs_seqno_r;
  (void)zero_point;
  (void)checkpoint;
  return abs_seqno;
}
  1. tcp_receiver.hh
#pragma once

#include "reassembler.hh"
#include "tcp_receiver_message.hh"
#include "tcp_sender_message.hh"


class TCPReceiver
{
public:
  TCPReceiver() : isn( 0 ), fin( 0 ), is_isn_set( 0 ), is_last_substring( 0 ) {}
  /*
   * 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;
private:
  Wrap32 isn;             // 记录流的ISN位置
  Wrap32 fin;             // 记录流的FIN位置
  bool is_isn_set;        // 标记ISN是否被设置了
  bool is_last_substring; // 标记是否到达流的末尾
};
  1. tcp_receiver.cc
#include "tcp_receiver.hh"

using namespace std;

void TCPReceiver::receive( TCPSenderMessage message, Reassembler& reassembler, Writer& inbound_stream )
{
  // 当设置了SYN标志时,记录ISN,标记is_isn_set,此标记一旦设置就一直有效
  if ( message.SYN == true ) {
    isn = Wrap32( message.seqno );
    is_isn_set = true;
    message.seqno = message.seqno + 1; // 此时seqno指向ISN,因此需要重定向为有效载荷的第一个字符
  }
  // 当设置FIN标志时,记录FIN,标记is_last_substring,这只针对一个数据,因此没有FIN标志时,要移除is_last_substring标记
  if ( message.FIN == true ) {
    is_last_substring = true;
    fin = Wrap32( message.seqno + message.payload.size() );
  } else
    is_last_substring = false;
  // 把数据送进reassembler,first_index需要转换
  // first_index = absolute seqno - 1 , absolute seqno = seqno.unwrap
  // unwrap时的checkpoint使用_first_unassembled_index = Writer.bytes_pushed()
  if ( is_isn_set == true ) // ISN被设置后才能转换seqno,因此ISN没设置之前不能push
    reassembler.insert( message.seqno.unwrap( isn, inbound_stream.bytes_pushed() ) - 1,
                        message.payload,
                        is_last_substring,
                        inbound_stream );
  (void)reassembler;
  (void)inbound_stream;
}
TCPReceiverMessage TCPReceiver::send( const Writer& inbound_stream ) const
{
  TCPReceiverMessage tcpReceiverMessage;
  // 当ISN被设置之后,才设置ackno
  Wrap32 ackno
    = Wrap32::wrap( inbound_stream.bytes_pushed() + 1, isn ); // _first_unassembled_index先+1转成abs seqno,再wrap
  if ( is_isn_set == true )
    tcpReceiverMessage.ackno = ackno == fin ? ackno + 1 : ackno; // 特殊情况,ackno需要越过FIN
  tcpReceiverMessage.window_size
    = inbound_stream.available_capacity() > UINT16_MAX ? UINT16_MAX : inbound_stream.available_capacity(); // window_size的上限是UINT16_MAX
  (void)inbound_stream;
  return tcpReceiverMessage;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/350158.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

21.Arrays类

Arrays类 1. 概述2. 常见方法3. sort 方法的自定义排序4. 代码示例5. 输出结果6. 注意事项 1. 概述 Arrays类是Java中的一个工具类&#xff0c;位于java.util包中。 它提供了一组静态方法&#xff0c;用于操作数组。通过Arrays类&#xff0c;我们可以对数组进行复制、填充、排…

【第四天】蓝桥杯备战

题 1、求和2、天数3、最大缝隙 1、求和 https://www.lanqiao.cn/problems/1442/learning/ 解法&#xff1a;字符串方法的应用 import java.util.Scanner; // 1:无需package // 2: 类名必须Main, 不可修改public class Main {public static void main(String[] args) {Scann…

MSG3D论文解读

论文在stgcn与sta-lstm基础上做的。下面讲一下里面的方法&#xff1a; 1.准备工作 符号。这里是对符号进行解释。 一个人体骨骼图被记为G(v,E) 图卷积&#xff1a; 图卷积定义 考虑一种常用于处理图像的标准卷积神经网络 (CNN)。输入是像素网格。每个像素都有一个数据值向…

kubeSphere DevOps自定义容器 指定nodejs版本

✨✨✨✨✨✨ &#x1f380;前言&#x1f381;基于内置镜像构建&#x1f381;把镜像添加基础容器中&#x1f381;检查容器是否配置成功&#x1f381;不生效的原因排查&#x1f381;按步骤执行如下命令 &#x1f380;前言 由于我本地的开发环境node是16.18.1,而自带容器node的版…

项目中遇到通过域名访问服务提示 Service name unknow

目录 项目中遇到通过域名访问服务提示 Service name unknow 1.问题描述2.问题原因3.解决思路4.解决方案文章所属专区 项目问题解决 1.问题描述 在CentOS 系统环境下 项目中遇到通过域名访问服务提示 Service name unknow,但是 网络是连通的 通过ping 和telnet都能够验证。 …

win10+elasticsearch8.12 安装教程

Elasticsearch是一种搜索引擎&#xff0c;本地安装完成之后&#xff0c;可使用其他编程语言&#xff08;例如python&#xff09;与elasticsearch建立连接&#xff0c;然后使用python脚本搜索elasticsearch中的数据 1下载 elasticsearch elasticsearch最新版官网下载链接 点击…

Pandas.DataFrame.product() 乘积(累乘积) 详解 含代码 含测试数据集 随Pandas版本持续更新

关于Pandas版本&#xff1a; 本文基于 pandas2.2.0 编写。 关于本文内容更新&#xff1a; 随着pandas的stable版本更迭&#xff0c;本文持续更新&#xff0c;不断完善补充。 传送门&#xff1a; Pandas API参考目录 传送门&#xff1a; Pandas 版本更新及新特性 传送门&…

让B端管理软件既美观又实用的解决方案来了

hello宝子们...我们是艾斯视觉擅长ui设计和前端开发10年经验&#xff01;希望我的分享能帮助到您&#xff01;如需帮助可以评论关注私信我们一起探讨&#xff01;致敬感谢感恩&#xff01; 让B端管理软件既美观又实用的解决方案来了 在当今数字化时代&#xff0c;B端管理软件已…

Docker容器部署OpenCV,打造高效可移植的计算机视觉开发环境

推荐 海鲸AI-ChatGPT4.0国内站点&#xff1a;https://www.atalk-ai.com 前言 在计算机视觉领域&#xff0c;快速部署和测试算法是研究和开发的关键。OpenCV作为一个强大的开源计算机视觉库&#xff0c;广泛应用于各种图像处理和视频分析任务。然而&#xff0c;配置OpenCV环境可…

计算机毕业设计 | SpringBoot 求职招聘管理系统(附源码)

1&#xff0c;绪论 1.1 开发背景 高学历人群是网络求职者的主体&#xff0c;且结构趋向固定。而在疫情肆虐的今日&#xff0c;线上招聘成了越来越多企业和个人选择的方式。在疫情期间线下招聘转为线上招聘&#xff0c;是疫情防控的需要。不能否定的是新的招聘模式的出现一定会…

智慧应急消防柜的作用

在现代社会&#xff0c;科技的不断进步带来了许多便利与改变。智能化的产品不仅给我们的生活带来了便捷&#xff0c;也让我们对各个领域的发展有了更高的期待。而在这种场景下&#xff0c;智慧应急消防柜作为智慧城市新型基础设施的必备品&#xff0c;正逐渐受到更多关注。 智能…

《游戏-03_3D-开发》之—新输入系统人物移动攻击连击

本次修改unity的新输入输出系统。本次修改unity需要重启&#xff0c;请先保存项目&#xff0c; 点击加号起名为MyCtrl&#xff0c; 点击加号设置为一轴的&#xff0c; 继续设置W键&#xff0c; 保存 生成自动脚本&#xff0c; 修改MyPlayer代码&#xff1a; using UnityEngine;…

设计模式二(工厂模式)

本质&#xff1a;实例化对象不用new&#xff0c;用工厂代替&#xff0c;实现了创建者和调用者分离 满足&#xff1a; 开闭原则&#xff1a;对拓展开放&#xff0c;对修改关闭 依赖倒置原则&#xff1a;要针对接口编程 迪米特原则&#xff1a;最少了解原则&#xff0c;只与自己直…

DDPM的一点笔记

1 Title Denoising Diffusion Probabilistic Models&#xff08;Jonathan Ho、Ajay Jain、Pieter Abbeel&#xff09; 2 Conclusion This paper present high quality image synthesis results using diffusion probabilistic models, a class of latent variable models insp…

【Qt】—— Qt开发环境的搭建

目录 &#xff08;一&#xff09;Qt的开发⼯具概述 1.1 Qt Creator 1.2 Visual Studio 1.3 Eclipse &#xff08;二&#xff09;Qt SDK的下载和安装 2.1 QtSDK的下载 2.2 QtSDK的安装 2.3 验证QtSDK安装是否成功 2.4 Qt环境变量配置 &#xff08;一&#xff09;Qt的…

yolov8 opencv dnn部署 github代码

源码地址 本人使用的opencv c github代码,代码作者非本人 实现推理源码中作者的yolov8s.onnx 推理条件 windows 10 Visual Studio 2019 Nvidia GeForce GTX 1070 opencv4.7.0 (opencv4.5.5在别的地方看到不支持yolov8的推理&#xff0c;所以只使用opencv4.7.0) c部署 先将…

一、防御保护---信息安全概述

一、网络安全防御---信息安全概述 1.信息安全现状及挑战1.1 网络空间安全市场在中国&#xff0c;潜力无穷1.2 数字化时代威胁升级1.3 传统安全防护逐步失效1.4 安全风险能见度不足1.5 缺乏自动化防御手段1.6 网络安全监管标准愈发严苛 2.信息安全概述2.1 简介2.2 常见的网络安全…

分币不花,K哥带你白嫖海外代理 ip!

前言 近来&#xff0c;国内的数据采集环境越来越严峻&#xff0c;不是“非法入侵计算机信息系统”&#xff0c;就是“侵犯公民个人隐私信息”&#xff0c;一个帽子砸下来&#xff0c;直接就“包吃包住”&#xff0c;推荐阅读一下 【K哥爬虫普法专栏】。虽然大伙常说“搏一搏单…

weak_ptr 与 一个难发现的错误(循环依赖问题)笔记

推荐B站视频&#xff1a;7.weak_ptr与一个非常难发现的错误_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV18B4y187uL/?p7&spm_id_frompageDriver&vd_sourcea934d7fc6f47698a29dac90a922ba5a3一、weak_ptr weak_ptr并不拥有所有权并不能调用 -> 和 解引…

【MySQL】如何使用图形化界面DataGrip操作数据库

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 ​&#x1f4ab;个人格言:“没有罗马,那就自己创造罗马~” #mermaid-svg-W5JDg0WA1tjEP66Y {font-family:"trebuchet ms",verdana,arial,sans-serif;font-siz…