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

news2024/10/2 11:54:47

🕺作者: 主页

我的专栏
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;
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据结构(C语言版)代码实现(四)——静态单链表的部分代码实现

目录 参考材料、格式 头文件SLinkList.h 库、宏定义、函数类型声明 线性表的静态单链表存储结构 按值查找 初始化静态链表 分配空间 回收空间 打印已用链表中的元素 求集合(A-B)U(B-A)中的元素&#xff08;重点介绍&#xff09; 调试过程 修改报错与警告 调试 完整…

何恺明 ResNet 引用量正式破20万!!!

注: 本文转自微信公众号 BravoAI (专注AI资讯和技术分享), 原文网址: 何恺明 ResNet 引用量正式破20万!!!, 扫码关注公众号 谷歌学术显示, 截止到 2024年1月26日, 何凯明 ResNet 一文引用量正式突破 20W!!! 更为惊人的是, 从论文发表到今天, 不过7年!!!‍‍‍‍‍‍‍‍‍‍‍‍…

6轴机器人运动正解-逆解控制【1】——三种控制位姿的方式

概览&#xff1a; 通过运动学正解控制机器人运动通过运动学逆解控制机器人运动一个简单的物体搬运&#xff08;沿轨迹运动&#xff09; 后续会陆续更新&#xff08;本例仅供学习交流用&#xff09; 一、6轴机器人 二、运动正解控制 通过修改各个轴的角度&#xff0c;实现末…

演示黄金票据,使用普通账户导入黄金票据创建域管理员

前提域搭建好了&#xff0c;域名是lin.com 首先我进入的是本机的用户不是域用户 我要是用本地用户&#xff0c;本地用户拿的票告诉我们这个TGS服务说我是域管账户administrator&#xff08;需要拿到域用户的哈希&#xff09; 此时进入到预控主机中&#xff08;人家是正儿八经…

Google Chrome RCE漏洞 CVE-2020-6507 和 CVE-2024-0517 流程分析

本文深入研究了两个在 Google Chrome 的 V8 JavaScript 引擎中发现的漏洞&#xff0c;分别是 CVE-2020-6507 和 CVE-2024-0517。这两个漏洞都涉及 V8 引擎的堆损坏问题&#xff0c;允许远程代码执行。通过EXP HTML部分的内存操作、垃圾回收等流程方式实施利用攻击。 CVE-2020-…

计算机网络 第6章(应用层)

系列文章目录 计算机网络 第1章&#xff08;概述&#xff09; 计算机网络 第2章&#xff08;物理层&#xff09; 计算机网络 第3章&#xff08;数据链路层&#xff09; 计算机网络 第4章&#xff08;网络层&#xff09; 计算机网络 第5章&#xff08;运输层&#xff09; 计算机…

MySQL十部曲之一:MySQL概述及手册说明

文章目录 数据库、数据库管理系统以及SQL之间的关系关系型数据库与非关系型数据库手册语法约定 数据库、数据库管理系统以及SQL之间的关系 名称说明数据库&#xff08;Database&#xff09;即存储数据的仓库&#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…

xshell无法连接linux,查询本机ip时出现<NO-CARRIER,BROADCAST,MULTICAST,UP>

在用xshell连接虚拟机VMware中的linux时&#xff0c;发现昨天还能连通的&#xff0c;今天连接不了了 我寻思应该是网卡配置出问题了&#xff0c;就去终端ip addr试了一下&#xff0c;果然发现问题&#xff0c;ip 查看网卡ens33就发现出现ens33:<NO-CARRIER,BROADCAST,MULTI…

操作符详解(上)

目录 操作符的分类 二进制和进制转换 2进制转10进制 10进制转2进制数字 2进制转8进制 2进制转16进制 原码、反码、补码 移位操作符 左移操作符 右移操作符 位操作符&#xff1a;&、|、^、~ 单目操作符 逗号表达式 操作符的分类 • 算术操作符&#xff1a; …

无法获得dpkg前端锁、Linux之E: 无法锁定管理目录(/var/lib/dpkg/),是否有其他进程正占用它?(解决方法)

无法获得dpkg前端锁的解决方法 sudo rm /var/lib/dpkg/lock sudo rm /var/lib/dpkg/lock-frontend sudo rm /var/cache/apt/archives/lock 输入以上三个命令即可解除占用。解除后&#xff0c;继续运行apt命令&#xff0c;已经顺利运行了。解除前端锁后&#xff0c;Linux之E: 无…

自动写作软件有哪些?一次性分享5个好用软件

自动写作软件有哪些&#xff1f;随着科技的不断发展&#xff0c;自动写作软件逐渐进入了人们的视野。这些软件能够根据用户提供的关键词和主题&#xff0c;自动生成一篇完整的文章。这对于需要大量内容创作者来说&#xff0c;无疑是一个福音。下面介绍一些知名的自动写作软件&a…

鸿蒙开发实战-手写文心一言AI对话APP

运行环境 &#xff08;后面附有API9版本&#xff0c;可修改后在HarmonyOS4设备上运行&#xff09; DAYU200:4.0.10.16 SDK&#xff1a;4.0.10.15 IDE&#xff1a;4.0.600 在DAYU200:4.0.10.16上运行 一、创建应用 1.点击File->new File->Create Progect 2.选择模版…

D. Gargari and Permutations

很好玩的一道类似LCS的DP 问题 定义dp(i) 为考虑最后一个字符串&#xff0c;且选择a&#xff08;i&#xff09;得到的最大LIS值 然后枚举所有小于i的位置&#xff0c;可以更新的条件是 所有的字符串中都有a[j]<a[i] 这个用map一处理就好了 #include<bits/stdc.h> usi…

EasyCVR视频融合平台雪亮工程视频智能监控方案设计与应用

随着科技的不断发展&#xff0c;视频监控已经成为城市安全防范的重要手段之一。为了提高城市安全防范水平&#xff0c;各地纷纷开展“雪亮工程”&#xff0c;即利用视频智能监控技术&#xff0c;实现对城市各个角落的全方位、全天候监控。本文将介绍一种雪亮工程视频智能监控方…

机器人学论文——智能施药机器人调研报告

目录 摘 要 Abstract 第一章&#xff1a;引言 1.1研究背景 1.2 研究意义 1.3文章架构 第二章&#xff1a;智能施药机器人发展现状 2.1引言 2.2 大田智能施药机器人发展现状 2.3 果园智能施药机器人发展现状 2.4 设施农业智能施药机器人发展现状 第三章&#xff1a;智能施药机器…

PCL-IO输入输入模块

IO输入输入模块 一、概述二、点云数据格式1. PCD 格式2. PLY 格式3. OBJ 格式4. STL 格式5. OFF 格式 三、读取3D文件1. API 总览2. 示例 四、保存3D文件1. API 总览2. 示例 一、概述 PCL 库提供了一个模块用来对3D数据进行读写操作&#xff0c;这个库提供了一个模块&#xff…

sony ps3 eye 摄像头win10、win11directShow补丁驱动,补充CL5.3驱动无法外部程序调用问题

最近把几年前&#xff0c;淘的sony ps3 eye 摄像头拿出来测试&#xff0c;发现升值了。原来4个打算做动捕用&#xff0c;结果发现安装完CL-Eye-Driver-5.3.0.0341驱动后&#xff0c;无法用外部程序驱动摄像头&#xff0c;后来知乎里发现有人解决了这个为题&#xff0c;是win10下…

2982. 找出出现至少三次的最长特殊子字符串 II

字典树思路 用字典树搞一下就好了&#xff0c;比如aaaaa &#xff1a; a存5次 aa 4次以此类推&#xff5e; 字典树板子复习&#xff1a;P8306 【模板】字典树 这里这个清空方式 很好 因为很多时候memset T #include<iostream> #include<cstring> using namesp…

1. MySQL 数据库

本章内容 关系型数据库基础 安装 MySQL 管理数据库和表 用户和权限管理 函数&#xff0c;存储过程&#xff0c;触发器和事件 MySQL 架构 存储引擎 服务器选项&#xff0c;系统和状态变量 优化查询和索引管理 锁和事务管理 日志管理 备份还原 MySQL 集群 压力测试…