socket编程UDP-实现滑动窗口机制与累积确认GBN
在下面博客中,我介绍了利用UDP模拟TCP连接、按数据包发送文件的过程,并附上完整源码。
socket编程UDP-文件传输&模拟TCP建立连接脱离连接(进阶篇)_udp socket发送-CSDN博客
下面博客实现了停等机制。
socket编程UDP-实现停等机制(接收确认、超时重传)-CSDN博客
本篇博客,我将在此基础上实现滑动窗口机制,完成客户端发送服务器接收的累积确认(GBN)。
目录
一、协议设计
1.思路概览
2.完整实例
二、核心代码
1.代码实现思路
2. 核心源码
3.可运行完整源码
三、运行演示
1.正常传输(收到正确序列号)
2.乱序抵达(出现丢包情况,收到偏大/偏小数据包)
一、协议设计
1.思路概览
1)对于发送端(客户端),发送窗口为N>1,每次发送的基准窗口设置为base(即每轮发送的最小序列值)。并且:
-
允许发出N个未得到确认的分组,连续发送而不等待接收端的回复
-
如果在定时范围内收到该轮最大的ack(expectedAck=base+N-1),立即更新基准窗口base=expectedAck+1,并且开始下一轮发送。(也就是说,即使定时器时间未到,也立刻开始下一轮发送)
-
如果在定时范围内没有收到该轮最大的ack,将base更新为这段时间收到的最大ack值+1,即base=max(getAck)+1.并且从base开始进行下一轮发送。
2)对于接收端(服务器端),接收窗口大小设置为1,因此每收到一个数据包,都会发送一次ack。为了处理丢包,设置buffer缓冲区,用于存储乱序抵达的包。
-
如果收到期待的数据包(seq==expectedseq,其中expectedseq=last\_ack+1),将数据写入文件,并检查缓冲区中是否存储有后续数据包的内容;如果有,将缓冲区的内容写入文件。依据已经写入文件的数据包序列号来更新expectedseq,并发送ack = expectedSeq - 1。
-
如果收到的数据包序列号大于期待值(seq>expectedseq),将数据暂存进缓冲区buffer,发送最后一次按序抵达的数据包对应的ack.
-
如果收到的数据包序列号小于期待值(seq<expectedseq),说明收到了重复的数据包,,只发送最后一次按序抵达的数据包对应的ack
2.完整实例
-
发送窗口大小设置为4,初始时客户端连续发送序列号为0,1,2,3的四个数据包。
-
图中的seq=0,seq=1的数据包按序抵达(seq==expectedseq,其中expectedseq=last\_ack+1),服务器端会发送对应的ack=0,ack=1.
-
图中seq=2的数据包丢失,于是当seq=3的数据包抵达时,服务器端收到了偏大的序号(seq=3>expectedseq=2)。服务器端会暂存seq=3的数据包到缓冲区中,并发送已经收到的最大正确序号(ack=1).
-
客户端一直期待收获到“ack=3”,等待一段时间没有收到,说明超时。于是基准窗口移动为收到的最大ack+1,即1+1=2,发送序列号为2,3,4,5的四个数据包。
-
服务器端收到seq=2的数据包后,由于之前暂存了seq=3的数据包,因此ack更新为3,将两个数据包一起写入文件,并发送ack=3.
-
服务器端再次收到seq=3的数据包,不会重复写入,依旧发送ack=3.
-
服务器端成功接收四个数据包,客户端收到期待的ack(ack=5),不再等待定时器到时,立刻更新基准窗口为6,开始下一轮发送。
二、核心代码
1.代码实现思路
服务器端为接收方,只需要简单地接收数据包并发送对应ack.
而客户端的实现较为复杂,主要逻辑如下图:
客户端每收到一个ack,就会比较ack与getACK的值,把最大ack赋给getACK.
如果客户端收到了期待的最大ack(即传输过程中没有出现丢包),会立即更新base并开始下一轮发送;
如果客户端未收到期待的最大ack,会陷入等待,定时器到时后会将base更新为getAck+1,已经读取过的数据包重新发送、未读取的数据包读取后再发送。
2. 核心源码
bool Sender::waitForAck() {std::unique_lock<std::mutex> lock(mtx);//如果 `ackReceived` 在超时之前变为 `true`,则 `wait\_for` 返回并继续执行后续代码;//如果超时后 `ackReceived` 仍为 `false`,则 `wait\_for` 也会返回。return cv.wait_for(lock, std::chrono::milliseconds(5*TIMEOUT), [this]() { return ackReceived.load() ; });//超时或者收到所有ack返回
}
void Sender::receiveAck() {Datagram ackPacket(SERVER_PORT,ROUTER_PORT);socklen_t len = sizeof(routerAddr);while (true) {if (recvfrom(sock, reinterpret_cast<char*>(&ackPacket), sizeof(ackPacket), 0, (struct sockaddr*)&routerAddr, &len) > 0) {if (ackPacket.flag == 0 && ackPacket.validateChecksum(clientAddr.sin_addr.S_un.S_addr, routerAddr.sin_addr.S_un.S_addr)) {if(ackPacket.ack==65535){continue;}std::lock_guard<std::mutex> lock(mtx);std::cout << "收到ack=" << ackPacket.ack << std::endl;if(ackPacket.ack>getAck){getAck=ackPacket.ack;}if(ackPacket.ack==expectedAck){ackReceived = true;cv.notify_one();} }}}
}
void Sender::sendFile(const std::string& filename) {//.......base = 0;nextseq = 0;while (true) {//.......//1.基于窗口连续发送N条消息while (nextseq < base + WINDOW_SIZE && !file.eof()) {if(nextseq<3&&AckPacket.flag == 2&&AckPacket.validateChecksum(clientAddr.sin_addr.S_un.S_addr, routerAddr.sin_addr.S_un.S_addr))//2.如果此时又收到了SYN-ACK{//...重新发送}std::unique_lock<std::mutex> lock(mtx);ackReceived = false;expectedAck = base+WINDOW_SIZE-1;Datagram packet;//默认构造,从客户端发往路由器端packet.seq = nextseq;file.read(packet.data, BUFFER_SIZE);packet.dataSize = static_cast<int>(file.gcount());packet.flag = 0;window[nextseq] = packet;//window.emplace(nextseq, packet);sendPacket(packet);std::cout << "发送数据包.SEQ=" << packet.seq <<",校验码="<< packet.checksum << std::endl;nextseq++;lock.unlock();}std::this_thread::sleep_for(std::chrono::milliseconds(TIMEOUT));// 2.结束条件:如果所有包都被确认,则跳出if (base == nextseq && file.eof()) break;if (waitForAck()) {std::unique_lock<std::mutex> lock(mtx);base = base + WINDOW_SIZE;std::cout << "base窗口后移为:" << base << ",开始下一轮发送" << std::endl;} else {std::unique_lock<std::mutex> lock(mtx);if(getAck==-1){base=0;}else{base =getAck+1;}std::cout << "未收到所有ack,base窗口后移为:" << base << ",重新发送此部分" << std::endl;for (int i = base; i < nextseq; ++i) {sendPacket(window[i]);std::cout << "发送数据包.SEQ=" << window[i].seq << ",校验码=" << window[i].checksum << std::endl;}}}//.......}
3.可运行完整源码
已上传github:
https://github.com/yeyeyeyeye-zhang/Computer-Network/tree/main/lab3-2/codes
三、运行演示
在src目录下输入:
g++ -o cs main.cpp Datagram.cpp Sender.cpp Receiver.cpp -lws2_32
1.正常传输(收到正确序列号)
客户端发送数据包,收到期待ack值,窗口正常后移的情况
服务器端收到期待序列号的数据包,正常发送对应ack的情况
2.乱序抵达(出现丢包情况,收到偏大/偏小数据包)
客户端发送时出现丢包现象,丢失seq=493的数据包,收到的ack值为492.定时器超时后,base窗口后移为493,发送从493到496的数据包。
服务器端未收到seq=493的数据包,之后再收到seq=494,495的数据包都仅发送ack=492.
相关文章:
socket编程UDP-实现滑动窗口机制与累积确认GBN
在下面博客中,我介绍了利用UDP模拟TCP连接、按数据包发送文件的过程,并附上完整源码。 socket编程UDP-文件传输&模拟TCP建立连接脱离连接(进阶篇)_udp socket发送-CSDN博客 下面博客实现了停等机制。 socket编程UDP-实现停…...
乐观锁与悲观锁的概念
在多线程或多进程并发访问同一资源的情况下,为了防止数据的不一致性和竞态条件,常常需要使用锁机制来控制并发访问。锁机制大致可以分为 乐观锁(Optimistic Locking)和 悲观锁(Pessimistic Locking)。这两种…...
考研数学【线性代数基础box(数二)】
本文是对数学二线性代数基础进行总结,一些及极其简单的被省略了,代数的概念稀碎,不如高数关联性高,所以本文仅供参考,做题请从中筛选! 本文为初稿,后面会根据刷题和自己的理解继续更新 高数&a…...
游戏引擎学习第45天
仓库: https://gitee.com/mrxiao_com/2d_game 回顾 我们刚刚开始研究运动方程,展示了如何处理当人物遇到障碍物时的情况。有一种版本是角色会从障碍物上反弹,而另一版本是角色会完全停下来。这种方式感觉不太自然,因为在游戏中,…...
基于 mzt-biz-log 实现接口调用日志记录
🎯导读:mzt-biz-log 是一个用于记录操作日志的通用组件,旨在追踪系统中“谁”在“何时”对“何事”执行了“何种操作”。该组件通过简单的注解配置,如 LogRecord,即可实现接口调用的日志记录,支持成功与失败…...
无人设备之RTK地面基站篇
一、定义与功能 RTK地面基站是一种通过差分定位技术来实现GPS等全球导航卫星系统信号精确定位的设备。它通过与无人设备上的流动站进行实时数据通信,利用载波相位差分原理,消除卫星定位过程中的大部分公共误差,如卫星轨道误差、电离层延迟、对…...
TMS320C55x DSP芯片结构和CPU外围电路
第2章 DSP芯片结构和CPU外围电路 文章目录 第2章 DSP芯片结构和CPU外围电路TMS320C55x处理器的特点TMS320c55x CPU单元指令缓冲(Instruction Buffer Unit) I单元程序流程(Program Flow Unit) P单元地址数据(Address-data Flow Unit) A单元数据计算(Data Computation Unit) D单元…...
【CC2530开发基础篇】继电器模块使用
一、前言 1.1 开发背景 本实验通过使用CC2530单片机控制继电器的吸合与断开,深入了解单片机GPIO的配置与应用。继电器作为一种常见的电气控制元件,广泛用于自动化系统中,用于控制大功率负载的开关操作。在本实验中,将通过GPIO口…...
3D 生成重建035-DiffRF直接生成nerf
3D 生成重建035-DiffRF直接生成nerf 文章目录 0 论文工作1 论文方法2 实验结果 0 论文工作 本文提出了一种基于渲染引导的三维辐射场扩散新方法DiffRF,用于高质量的三维辐射场合成。现有的方法通常难以生成具有细致纹理和几何细节的三维模型,并且容易出…...
安宝特分享 | AR技术助力医院总院与分院间的远程面诊
随着科技的迅猛发展,增强现实(AR)技术在各行各业的应用愈发广泛,特别是在医疗领域,其潜力和价值正在被不断挖掘。在现代医疗环境中,患者常常面临“看病难、看病远、看病急”等诸多挑战,而安宝特…...
【功能安全】硬件常用安全机制
目录 安全机制分类: ECC内存保护: 看门狗定时器WDT 看门狗的诊断覆盖率 程序流监控 软件自检<...
linux上qt打包(二)
sudo apt install git 新建一个文件夹 名为xiazai, chmod -R 777 xiazai cd xiazai 并进入这个文件夹,然后clone git clone https://github.com/probonopd/linuxdeployqt.git 此处可能要fanQiang才能下 cd linuxdeployqt文件夹 下载平台需要的…...
Vue3 左右2栏的宽度 比例resize
Vue3, 页面左右2栏布局,用vue-resizer.页面效果如下图。 安装 npm i vue-resizer引入 import { DragCol, DragRow, ResizeCol, ResizeRow, Resize } from vue-resizer<DragCol height"100%" width"100%" :leftPercent"15">…...
企业车辆管理系统(源码+数据库+报告)
一、项目介绍 352.基于SpringBoot的企业车辆管理系统,系统包含两种角色:管理员、用户,系统分为前台和后台两大模块 二、项目技术 编程语言:Java 数据库:MySQL 项目管理工具:Maven 前端技术:Vue 后端技术&a…...
LeetCode 1847.最近的房间:有序集合
【LetMeFly】1847.最近的房间:有序集合 力扣题目链接:https://leetcode.cn/problems/closest-room/ 一个酒店里有 n 个房间,这些房间用二维整数数组 rooms 表示,其中 rooms[i] [roomIdi, sizei] 表示有一个房间号为 roomIdi 的…...
C05S07-Tomcat服务架设
一、Tomcat 1. Tomcat概述 Tomcat也是一个Web应用程序,具有三大核心功能。 Java Servlet:Tomcat是一个Servlet容器,负责管理和执行Java Servlet、服务端的Java程序,处理客户端的HTTP请求和响应。Java Server:服务端…...
Vscode搭建C语言多文件开发环境
一、文章内容简介 本文介绍了 “Vscode搭建C语言多文件开发环境”需要用到的软件,以及vscode必备插件,最后多文件编译时tasks.json文件和launch.json文件的配置。即目录顺序。由于内容较多,建议大家在阅读时使用电脑阅读,按照目录…...
mac电脑可以使用的模拟器
BlueStacks Air 推荐-》亲测可用 BlueStacks Air https://www.bluestacks.com 支持macOS/Windows,刚新增了对Apple Silicon系列M芯片的支持 GameLoop https://www.gameloop.com/ 支持 macOS/Windows Genymotion https://www.genymotion.com/ 支持Android/macO…...
vertx idea快速使用
目录 1.官网下载项目 2.修改代码 2.1拷贝代码方式 为了能够快速使用,我另外创建一个新的maven项目,将下载项目的src文件和pom文件拷贝到新建的maven项目。 2.2删除.mvn方式 3.更新配置 4.配置application 5.idea启动项目 1.官网下载项目 从vert…...
selenium 在已打开浏览器上继续调试
关闭浏览器,终端执行如下指令,--user-data-dir换成自己的User Data路径 chrome.exe --remote-debugging-port9222 --user-data-dir"C:\Users\xxx\AppData\Local\Google\Chrome\User Data" 会打开浏览器,打开百度,如下状…...
RequestContextHolder 与 HttpServletRequest 的联系
1. 什么是 RequestContextHolder? RequestContextHolder 是 Spring 框架 提供的一个工具类,用于在当前线程中存储和获取与请求相关的上下文信息。它是基于 ThreadLocal 实现的,能够保证每个线程独立存储和访问请求信息。 与 HttpServletReq…...
力扣hot100——普通数组
53. 最大子数组和 class Solution { public:int maxSubArray(vector<int>& nums) {int n nums.size();int ans nums[0];int sum 0;for (int i 0; i < n; i) {sum nums[i];ans max(ans, sum);if (sum < 0) sum 0;}return ans;} }; 最大子数组和…...
本地部署大模型QPS推理测试
目录 1、测试环境1.1、显卡1.2、模型1.3、部署环境1.3.1、docker1.3.2、执行命令 2、测试问题2.1、20字左右问题2.2、50字左右问题2.3、100字左右问题 3、测试代码3.1、通用测试代码3.2、通用测试代码(仅供参考) 4、测试结果4.1、通用测试结果4.2、RAG测…...
内存、硬盘、DRAM、FLASH
内存 内存是计算机系统中用于临时存储和快速存取当前正在处理的数据和指令的组件,属于临时存储设备,它在计算机运行时用于存储活跃的程序和数据。内存的性能直接影响计算机的处理速度和响应能力。 内存的类型主要分为: DRAM(动态随…...
全景图转6面体图 全景图与6面体图互转
目录 图片转360度全景中心图 依赖项: 库的使用方法: 源代码: 全景图拆成6面体图: 全景图,转6面体,再转全景图: 图片转360度全景中心图 原图: 效果图: 依赖项: pip install py360convert pip install numpy==2.2 库的使用方法: https://g...
【psutil模块02】Python运维模块之系统进程管理方法
系统进程管理方法 获取当前系统的进程信息,包括进程的启动时间、查看或设置CPU亲和度、内存使用率、IO信息、socket连接、线程数等。 1.进程信息 psutil.pids()获取所有PID,使用psutil.Process()接收单个进程的PID,获取进程名、路径、状态、系统资源等…...
Java-08
类的抽象是将类的实现和使用分离, 而类的封装是将实现的细节封装起来并且对用户隐藏,用户只需会用就行。 类的合约指的是从类外可以访问的方法和数据域的集合以及与其这些成员如何行为的描述 isAlive()方法的返回值类型为布尔型(Boolean)。这个方法用于…...
四轴用的无刷电机到底是属于直流电机还是交流电机?
四轴用的无刷电机因其高效、稳定、体积小巧等特点,成为了广泛应用的动力系统之一。尽管其名称中包含“直流”二字,但无刷电机到底是属于直流电机还是交流电机,这一问题常常引发人们的探讨与困惑。 一、无刷电机的工作原理 首先,…...
Redis中的Hot key排查和解决思路
什么是Hot key Hot key其实就是被频繁访问的key,比普通的key访问量要高于十倍或者几十倍不等。例如: QPS集中在特定的Key:实例的总QPS(每秒查询率)为10,000,而其中一个Key的每秒访问量达到了7,000。带宽使…...
CMake 保姆级教程(上)
整理自 视频 【CMake 保姆级教程【C/C】】 https://www.bilibili.com/video/BV14s4y1g7Zj/?p5&share_sourcecopy_web&vd_source6eb8f46d194c5ef9f89d3331f623a9c3 1、cmake简介 源文件(.cpp / .c)要经过 工具链 1.1 工具链 1、预处理&#…...
C++类模板的应用
template <class T> class mylist{ public: // 这是一个链表的节点 struct Link{ T val; Link* next; } 增 :insert(T val) 在链表中创建新节点,节点上保存的数据为 val 删:remove(T val) 移除链表中数据为 val 的节点 改: operator[](…...
Ubuntu 18.04无有线图表且无法设置有线网络
问题背景: 今天在登陆自己的虚拟机Ubuntu系统的时候突然出现 有线连接无法连接的问题,有线连接的图标变为没有了,无法点击网络菜单的Setting模块选项。我的虚拟机有线网络连接方式是NAT方式。 没有如下有线连接图标 解决方法: …...
QoS分类和标记
https://zhuanlan.zhihu.com/p/160937314 1111111 分类和标记是识别每个数据包优先级的过程。 这是QoS控制的第一步,应在源主机附近完成。 分组通常通过其分组报头来分类。下图指定的规则仔细检查了数据包头 : 下表列出了分类标准: 普通二…...
企业内训|阅读行业产品运营实战训练营-某运营商数字娱乐公司
近日,TsingtaoAI公司为某运营商旗下数字娱乐公司组织的“阅读行业产品运营实战训练营”在杭州落下帷幕。此次训练营由TsingtaoAI资深互联网产品专家程靖主持。该公司的业务骨干——来自内容、市场、业务、产品与技术等跨部门核心岗位、拥有8-10年实战经验的中坚力量…...
杭州乘云联合信通院发布《云计算智能化可观测性能力成熟度模型》
原文地址:杭州乘云联合中国信通院等单位正式发布《云计算智能化可观测性能力成熟度模型》标准 2024年12月3日,由全球数字经济大会组委会主办、中国信通院承办的 2024全球数字经济大会 云AI计算创新发展大会(2024 Cloud AI Compute Ignite&…...
SimAI万卡集群模拟器,LLM大模型训练通信计算模拟
SimAI,是阿里巴巴构建的一个统一的模拟器,旨在大规模精确有效地模拟LLM训练过程。通过将训练框架、内核计算和集体通信库有选择地高保真集成到仿真过程中,SimAI在仿真中实现了高精度。 简单点来说,SimAI就是模拟,大模…...
Axure9设置画布固定
在使用AxureRP9设计原型时,如果遇到画布在拖动时变得难以控制,可以尝试在Windows系统中通过‘文件’>‘首选项’,或在Mac系统中通过‘AxureRP9’>‘偏好设置’进行设置,以稳定画布的行为。 现象 页面底层的画布࿰…...
window.getSelection() 获取划线内容并实现 dom 追随功能
功能:鼠标对一段文本中某些文字进行划线之后,需要在当前划线文本处出现一个功能按钮显示对划线内容进行操作,比如收藏、添加样本库等功能。 一、需要了解的鼠标事件对象属性 给 dom 元素注册鼠标事件之后,会有 event 属性&#…...
mybatis-plus超详细讲解
mybatis-plus (简化代码神器) 地址:https://mp.baomidou.com/ 目录 mybatis-plus 简介 特性 支持数据库 参与贡献 快速指南 1、创建数据库 mybatis_plus 2、导入相关的依赖 3、创建对应的文件夹 4、编写配置文件 5、编写代码 …...
浏览器可以直接请求 websocket
一、原生支持 浏览器原生支持 WebSocket 协议,这使得开发者可以直接在 JavaScript 代码中使用 WebSocket 来建立与服务器的双向通信通道。 const socket new WebSocket("ws://localhost:8080");socket.addEventListener("open", function (e…...
* 和 .* 的区别(MATLAB)
在 MATLAB 中,* 和 .* 都是用来进行乘法操作的运算符,但它们有不同的应用场景。我们将从数学和编程的角度详细解析这两者的区别,并且讲解 MATLAB 中 . 运算符的其他常见用法。 1. * 和 .* 的区别 *:矩阵乘法(线性代数…...
51c视觉~合集30
我自己的原文哦~ https://blog.51cto.com/whaosoft/12059371 #SaRA 修改一行代码就能实现高效微调!上海交大&腾讯开源:兼顾原始生成和下游任务 仅修改一行训练代码即可实现微调过程。 文章链接:https://arxiv.org/pdf/2409.06633 …...
JVM虚拟机总揽
为什么 Java 要在虚拟机里运行? 先说结论: 可以一次编译,在各个硬件平台如 Windows_x64、Linux_aarch64)都可以执行建立一个托管环境(Managed Runtime),这个托管环境能够代替我们处理一些代码…...
PCL点云库入门——PCL库可视化之PCLVisualizer类显示复杂点云信息等(持续更新)
1、PCLVisualizer类可视化 PCLVisualizer类作为PCL库可视化到的高级功能,不仅支持点云等数据的可视化,还提供了丰富的交互功能和自定义选项,如颜色调整、视角切换、标注添加等。用户可以通过PCLVisualizer类轻松实现复杂的数据分析和处理任务…...
Hugface国内镜像
问题: urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(hosthuggingface.co, port443): Max retries exceeded with url: /Salesforce/blip-image-captioning-base/resolve/main/preprocessor_config.json (Caused by ProxyError(Cannot connect to proxy.,…...
Vue3 重置ref或者reactive属性值
需要重新定义一个对象绑定复制给原对象 。 实例代码: const data () > ({groupId: ,groupCode: ,groupName: ,groupType: ,});const formData ref(data());//重置对象值 const reset()>{Object.assign(formData, data()…...
前端的Python入门指南(完):错误和异常处理策略及最佳实践
《前端的 Python 入门指南》系列文章: (一):常用语法和关键字对比(二):函数的定义、参数、作用域对比(三):数据类型对比 - 彻底的一切皆对象实现和包装对象异…...
c++:std::map下标运算符的不合理使用
这是我分析之前遗留代码时发现的一个隐藏点;不过我并不认为这样使用std::map是合理的。 看看简化后的代码,v1、v2的值应该是多少呢? #include <map>std::map<int, int> cm[2];int get_cm_value(int device, int ctrl) { auto …...
音频数据采样入门详解 - 给Python初学者的简单解释
音频数据采样入门详解 - 给Python初学者的简单解释 声音是如何变成数字的?什么是采样率?为什么要懂这个?Python小例子总结 大家好!今天我们来聊一个有趣的话题:音频数据是如何在计算机中处理的。让我用最简单的方式来解…...
vue el-dialog实现可拖拉
el-dialog实现拖拉,每次点击度居中显示,以下贴出代码具体实现,我是可以正常拖拉并且每次度显示在中间,效果还可以,需要的可以丢上去跑跑 组件部分: <el-dialog:visible.sync"dialogVisible"…...