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.

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【现代服务端架构】传统服务器 对比 Serverless

在现代开发中&#xff0c;选择合适的架构是至关重要的。两种非常常见的架构模式分别是 传统服务器架构 和 Serverless。它们各有优缺点&#xff0c;适合不同的应用场景。今天&#xff0c;我就带大家一起对比这两种架构&#xff0c;看看它们的差异&#xff0c;并且帮助你选择最适…

概率论得学习和整理24:EXCEL的各种图形,统计图形

目录 0 EXCEL的各种图形&#xff0c;统计图形 1 统计图形 / 直方图 / 其实叫 频度图 hist最合适(用原始数据直接作图) 1.1 什么是频度图 1.2 如何创建频度图&#xff0c;一般是只选中1列数据&#xff08;1个数组&#xff09; 1.3 如何修改频度图的宽度 1.4 hist图的一个特…

【第三节】Git 基本操作指南

目录 前言 一、获取与创建项目 1.1 git init 1.2 git clone 二、基本快照操作 2.1 git add 2.2 git status 2.3 git diff 2.4 git commit 2.5 git reset HEAD 三、 文件管理 3.1 git rm 3.2 git mv 四、Git 文件状态 5.1 工作目录 5.2 暂存区 5.3 本地仓库 5…

el-table 多表头+跨行跨列案例

效果&#xff1a; 代码&#xff1a; index.vue <template><div class"my-table"><el-tablev-loading"table.loading":data"table.data"bordersize"mini":header-cell-style"headerCellStyle":span-method&qu…

华为FreeBuds Pro 4丢了如何找回?(附查找功能使用方法)

华为FreeBuds Pro 4查找到底怎么用&#xff1f;华为FreeBuds Pro 4有星闪精确查找和离线查找&#xff0c;离线查找功能涵盖播放铃声、导航定位、星闪精确查找、上线通知、丢失模式、遗落提醒等。星闪精确查找是离线查找的子功能&#xff0c;当前仅华为FreeBuds Pro 4充电盒支持…

游戏引擎学习第43天

仓库 https://gitee.com/mrxiao_com/2d_game 介绍运动方程 今天我们将更进一步&#xff0c;探索运动方程&#xff0c;了解真实世界中的物理&#xff0c;并调整它们&#xff0c;以创建一种让玩家感觉愉悦的控制体验。这并不是在做一个完美的物理模拟&#xff0c;而是找到最有趣…

jenkins 出现 Jenkins: 403 No valid crumb was included in the request

文章目录 前言解决方式:1.跨站请求为找保护勾选"代理兼容"2.全局变量或者节点上添加环境变量3.&#xff08;可选&#xff09;下载插件 the strict Crumb Issuer plugin4.重启 前言 jenkins运行时间长了&#xff0c;经常出现点了好几次才能构建&#xff0c;然后报了Je…

SpringAI人工智能开发框架001---SpringAI框架介绍_支持文本到图像_音频到文本_聊天模型_嵌入模型_项目搭建

可以看到官网 SpringAi可以用来对接很多大模型,当然 SpringAI不支持国内大模型,但是SpringAI Alibaba可以,后面会写一个如何使用 SpringAI Alibaba的文章,很简单. 可以看到官网的介绍. 可以看到SpringAI 支持的模型. 有很多国外的.

【实验】【H3CNE邓方鸣】交换机端口安全实验+2024.12.11

实验来源&#xff1a;邓方鸣交换机端口安全实验 软件下载&#xff1a; 华三虚拟实验室: 华三虚拟实验室下载 wireshark&#xff1a;wireshark SecureCRT v8.7 版本: CRT下载分享与破解 文章目录 dot1x 开启802.1X身份验证 开启802.1X身份验证&#xff0c;需要在系统视图和接口视…

Web页面的请求历程

文章目录 1 因特网协议栈2 Web页面的请求历程 1 因特网协议栈 协议栈常用协议应用层HTTP协议、DNS协议、DHCP协议传输层TCP协议、UDP协议网络层IP协议、NAT协议、ICMP协议、BGP协议、OSPF协议数据链路层ARP协议、以太网协议物理层各种电气特性的规定等 2 Web页面的请求历程 …

Redis - 消息队列 Stream

一、概述 消息队列 定义 消息队列模型&#xff1a;一种分布式系统中的消息传递方案&#xff0c;由消息队列、生产者和消费者组成消息队列&#xff1a;负责存储和管理消息的中间件&#xff0c;也称为消息代理&#xff08;Message Broker&#xff09;生产者&#xff1a;负责 产…

从构想到实现:EasyOne 多模态 AI 产品开发历程

在人工智能技术飞速发展的今天&#xff0c;智能产品和服务已经从单一的应用向多模态智能系统进化。随着大语言模型、计算机视觉、语音识别等领域的突破&#xff0c;开发集成多种 AI 技术的平台变得日益重要。为此&#xff0c;我们开发了 EasyOne&#xff0c;一个全新的 AI 多模…

【深度学习总结】使用PDF构建RAG:结合Langchain和通义千问

【深度学习总结】使用PDF构建RAG&#xff1a;结合Langchain和通义千问 使用平台&#xff1a;趋动云&#xff0c;注册送算力 前言 在大型语言模型&#xff08;LLMs&#xff09;应用领域&#xff0c;我们面临着大量挑战&#xff0c;从特定领域知识的匮乏到信息准确性的窘境&am…

ubuntu监测硬盘状态

安装smartmontools smartctl -l error /dev/sdk smartctl -i /dev/sda lshw -class disk smartctl -H /dev/sd 结果1&#xff1a; 结果2&#xff1a;PASSED&#xff0c;这表示硬盘健康状态良好 smartctl -a /dev/sdb sdk lsblk blkid 测试写入速度 time dd if/dev/zero of…

易语言OCR证件照文字识别

一.引言 文字识别&#xff0c;也称为光学字符识别&#xff08;Optical Character Recognition, OCR&#xff09;&#xff0c;是一种将不同形式的文档&#xff08;如扫描的纸质文档、PDF文件或数字相机拍摄的图片&#xff09;中的文字转换成可编辑和可搜索的数据的技术。随着技…

【智体OS】官方上新发布智体机器人:使用rtrobot智体应用远程控制平衡车机器人

【智体OS】官方上新发布智体机器人&#xff1a;使用rtrobot智体应用远程控制平衡车机器人 dtns.network是一款主要由JavaScript编写的智体世界引擎&#xff08;内嵌了three.js编辑器的定制版-支持以第一视角浏览3D场馆&#xff09;&#xff0c;可以在浏览器和node.js、deno、e…

Three使用WebGPU的关键TSL

Three.js 使用 WebGPU 的关键 TSL TSL: three.js shader language 介绍 three.js 材质转为webgpu的关键流程, 从而引出 TSL. 1、关键类关系 WebGPURenderer|-- library: StandardNodeLibrary|-- _nodes: Nodes|-- _objects: RenderObjects|-- createRenderObject()StandardN…

东方通TongWeb7.0.4.9M4部署SuperMap iServer 11.2.1

一、软件版本 操作系统: CentOS Linux release 7.5.1804 (Core)JDK:11.0.18东方通&#xff1a;TongWeb7.0.4.9M4SuperMap iServer&#xff1a;11.2.1 JDK和TongWeb软件分享&#xff1a; 链接: https://pan.baidu.com/s/1HGDTPnPID0PEOMbg3FjTVQ?pwdbh8v 提取码: bh8v 东方通软…

医学预测模型的网页应用必要模块设计(重制版)

医学预测模型的网页应用必要模块设计&#xff08;重制版&#xff09; 刘岳鹏 摘要&#xff1a; 网页应用&#xff08;Web APP&#xff09;承载医学临床预测模型并在临床实践中实现与用户的互动&#xff0c;必要的功能模块设计将有助于Web APP更好地在临床实践中发挥其功能。在此…

【C++】反向输出一个四位数的深入探讨

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C 文章目录 &#x1f4af;前言&#x1f4af;问题描述&#x1f4af;我的实现方案代码实现核心思路解析示例执行过程 &#x1f4af;老师的实现方案代码实现代码特点与分析执行流程示例代码对比与深入分析 &#x1f4af;…