socket编程UDP-实现停等机制(接收确认、超时重传)
在下面博客中,我介绍了利用UDP模拟TCP连接、按数据包发送文件的过程,并附上完整源码。
socket编程UDP-文件传输&模拟TCP建立连接脱离连接(进阶篇)_udp socket发送-CSDN博客
下面博客实现的是滑动窗口机制:
socket编程UDP-实现滑动窗口机制与累积确认GBN-CSDN博客
本篇博客,我将在此基础上实现停等机制,完成客户端发送的接收确认、超时重传。
目录
一、停等机制的协议设计
二、停等机制的代码实现
1.实现思路
2.核心源码
3.可运行完整源码
三、运行演示
1.建立与断开连接
2.接收确认(无丢包)
3.丢包处理&超时重传
一、停等机制的协议设计

在设计中,客户端为文件发送方、服务器端为文件接收方。
每次客户端发送的数据包有唯一的序列号seq(随着数据包的发送不断递增), 如果服务器端收到新的数据包会发送对应的ack.(比如收到seq1就会发送ack1,收到seq2就会发送ack2).
所谓停等机制,就是发送方每轮只发送一个数据包,直到收到期待的ack(即与序列号对应的ack),才会发送下一个数据包。
如果发送方在定时器时间内没有收到期待的ack,将会重传这一数据包。(正如图中发送端重传seq2)
二、停等机制的代码实现
1.实现思路

接收确认和超时重传机制主要通过 ‘waitForAck‘、‘receiveAck‘和 ‘sendFile‘函数来完成。以下是实现过程的描述:
-
在 ‘receiveAck‘方法中,服务器会不断监听 ACK 消息。收到任何数据包后,首先验证其校
验和和 ACK 序列号是否匹配。如果验证成功,会将 ‘ackReceived‘设置为 ‘true‘,并通过条件变量通知 ‘waitForAck‘,使其能够退出等待状态。
-
‘sendFile‘方法负责逐个发送数据包,并在每次发送后调用‘waitForAck‘,等待接收 ACK 确认。每个数据包都包含一个序列号(‘seqNum‘),用于标识数据的顺序和确认接收的正确性。发送数据包后, ‘ackReceived‘标志被设置为 ‘false‘,并记录期望的 ACK 序列号。
-
‘waitForAck‘方法使用条件变量和超时机制,如果在设定的超时时间内未收到正确的 ACK 确认,便会返回 ‘false‘,触发重传逻辑;如果收到了正确ack,则会返回true.
2.核心源码
bool Sender::waitForAck(int seqNum) {std::unique_lock<std::mutex> lock(mtx);return cv.wait_for(lock, std::chrono::milliseconds(TIMEOUT), [this, seqNum]() { return ackReceived && expectedAck == seqNum; });
}
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.validateChecksum(clientAddr.sin_addr.S_un.S_addr, routerAddr.sin_addr.S_un.S_addr) && ackPacket.ack == expectedAck) {std::lock_guard<std::mutex> lock(mtx);std::cout<<"收到ACK,ack="<<ackPacket.ack<<std::endl;ackReceived = true;cv.notify_one();}}}
}
void Sender::sendFile(const std::string& filename) {//......int seqNum = 0;while (!file.eof()) {Datagram packet(CLIENT_PORT,ROUTER_PORT);packet.seq = seqNum;file.read(packet.data, BUFFER_SIZE);packet.dataSize = static_cast<int>(file.gcount());packet.flag = 0; // 数据包ackReceived = false;expectedAck = seqNum;//1.创建接收线程,避免第三次握手时ACK的丢包Datagram AckPacket(SERVER_PORT,ROUTER_PORT);if(seqNum<3){std::thread ackThread1(&Sender::receivePacket,this, std::ref(AckPacket));std::this_thread::sleep_for(std::chrono::milliseconds(TIMEOUT)); //休眠等一会儿ackThread1.detach();//修改}while (true) {if(AckPacket.flag == 2&&seqNum<3&&AckPacket.validateChecksum(clientAddr.sin_addr.S_un.S_addr, routerAddr.sin_addr.S_un.S_addr))//2.如果此时又收到了SYN-ACK{std::cout << "重新收到SYN-ACK包\n";Datagram ackPacket(CLIENT_PORT,ROUTER_PORT);ackPacket.flag = 3; // ACKsendPacket(ackPacket);std::cout << "重新发送ACK包,连接建立成功\n";std::this_thread::sleep_for(std::chrono::milliseconds(TIMEOUT)); //休眠等一会儿AckPacket.flag=1;}sendPacket(packet);std::cout << "发送数据包.SEQ=" << packet.seq <<",校验码="<< packet.checksum<<std::endl;std::this_thread::sleep_for(std::chrono::milliseconds(5*TIMEOUT)); //休眠等一会儿if (waitForAck(seqNum)) {break; // 收到ACK,跳出重传循环}std::cout << "ACK超时,重传数据包,SEQ=" << packet.seq << std::endl;}seqNum++;}//......
}
3.可运行完整源码
已上传github:
https://github.com/yeyeyeyeye-zhang/Computer-Network/tree/main/lab3-1/codes
三、运行演示
在src目录下输入:
g++ -o cs main.cpp Datagram.cpp Sender.cpp Receiver.cpp -lws2_32
1.建立与断开连接

客户端建立连接

服务器端建立连接

客户端断开连接

服务器端断开连接
2.接收确认(无丢包)

客户端正常发送与接收

服务器端正常接收与发送
3.丢包处理&超时重传

出现丢包后,超时,客户端重传数据包
相关文章:
socket编程UDP-实现停等机制(接收确认、超时重传)
在下面博客中,我介绍了利用UDP模拟TCP连接、按数据包发送文件的过程,并附上完整源码。 socket编程UDP-文件传输&模拟TCP建立连接脱离连接(进阶篇)_udp socket发送-CSDN博客 下面博客实现的是滑动窗口机制: sock…...
前端面试题目 (Node.JS-Express框架)[二]
在 Express 中如何使用 Passport.js 进行身份认证? Passport.js 是一个 Node.js 的身份验证中间件,它可以很容易地与 Express 集成。下面是一个简单的示例,展示了如何使用 Passport.js 进行基本的身份认证。 安装依赖 npm install express passport …...
防范TCP攻击:策略与实践
TCP(传输控制协议)是互联网通信的核心协议之一,它确保了数据在网络上的可靠传输。然而,TCP也容易成为各种网络攻击的目标,如SYN洪水攻击、TCP连接耗尽攻击等。本文将探讨如何通过配置防火墙规则、优化服务器设置以及采…...
3D 生成重建034-NerfDiff借助扩散模型直接生成nerf
3D 生成重建034-NerfDiff借助扩散模型直接生成nerf 文章目录 0 论文工作1 论文方法2 实验结果 0 论文工作 感觉这个论文可能能shapE差不多同时期工作,但是shapE是生成任意种类。 本文提出了一种新颖的单图像视图合成方法NerfDiff,该方法利用神经辐射场 …...
分布式 Paxos算法 总结
前言 相关系列 《分布式 & 目录》《分布式 & Paxos算法 & 总结》《分布式 & Paxos算法 & 问题》 参考文献 《图解超难理解的 Paxos 算法(含伪代码)》《【超详细】分布式一致性协议 - Paxos》 Basic-Paxos 基础帕克索斯算法…...
我的宝贵经验
在技术的浩瀚海洋中,一份优秀的技术文档宛如精准的航海图。它是知识传承的载体,是团队协作的桥梁,更是产品成功的幕后英雄。然而,打造这样一份出色的技术文档并非易事。你是否在为如何清晰阐释复杂技术而苦恼?是否纠结…...
geoserver 瓦片地图,tomcat和nginx实现负载均衡
在地理信息系统(GIS)领域,GeoServer作为一个强大的开源服务器,能够发布各种地图服务,包括瓦片地图服务。为了提高服务的可用性和扩展性,结合Tomcat和Nginx实现负载均衡成为了一个有效的解决方案。本文将详细…...
Jenkins 启动 程序 退出后 被杀死问题
参考 Spawning Processes From Build (jenkins.io) 解决jenkins脚本启动项目后进程被杀死_jenkins杀进程-CSDN博客...
SEGGER | 基于STM32F405 + Keil - RTT组件01 - 移植SEGGER RTT
导言 RTT(Real Time Transfer)是一种用于嵌入式中与用户进行交互的技术,它结合了SWO和半主机的优点,具有极高的性能。 使用RTT可以从MCU非常快速输出调试信息和数据,且不影响MCU实时性。这个功能可以用于很多支持J-Link的设备和MCU࿰…...
分布式开发学习
1、kratos的特点 gRPC:Kratos 默认支持 gRPC,提供高性能的远程调用能力,适用于微服务间通信。 HTTP :同时支持 HTTP/1.1 和 HTTP/2,方便微服务与外部系统交互。 Protocol Buffers: protoc 工具生…...
freeswitch(开启支持MCU视频会议,使用mod_av模块)
亲测版本centos 7.9系统–》 freeswitch1.10.9 本人freeswitch安装路径(根据自己的路径进入) /usr/local/freeswitch/etc/freeswitch场景说明: 有些场景想使用视频会议MCU融合画面进行开会使用方法: 第一步:下载插件 yum install -y epel-release yum install...
Vue3常见api使用指南(TS版)
defineProps() 和 defineEmits() 内置函数,无需import导入,直接使用。传入到 defineProps 和 defineEmits 的选项会从 setup 中提升到模块的范围。因此,传入的选项不能引用在 setup 范围中声明的局部变量(比如设置默认值时),但是…...
分布式 分布式事务 总结
前言 相关系列 《分布式 & 目录》《分布式 & 分布式事务 & 总结》《分布式 & 分布式事务 & 问题》 分布式事务 所谓分布式事务是指操作范围笼罩多个不同节点的事务。例如对于订单节点&库存节点而言,一次完整的交易需要同时调动两个节…...
onnx文件转pytorch pt模型文件
onnx文件转pytorch pt模型文件 1.onnx2torch转换及测试2.存在问题参考文献 从pytorch格式转onnx格式,官方有成熟的API;那么假如只有onnx格式的模型文件,该怎样转回pytorch格式? https://github.com/ENOT-AutoDL/onnx2torch提供了…...
智能座舱人机交互升级
我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 所谓鸡汤,要么蛊惑你认命,要么怂恿你拼命,但都是回避问题的根源&…...
RabbitMQ中点对点(Point-to-Point)通讯方式的Java实现
RabbitMQ是一个广泛使用的开源消息代理软件,它实现了高级消息队列协议(AMQP)。RabbitMQ支持多种消息传递模式,其中最基本的是点对点(Point-to-Point)通讯方式。在这种模式下,消息生产者将消息发…...
爬虫实战:获取1688接口数据全攻略
引言 在电商领域,数据的重要性不言而喻。1688作为中国领先的B2B电商平台,提供了海量的商品数据。通过爬虫技术获取这些数据,可以帮助企业进行市场分析、价格监控和供应链管理。本文将详细介绍如何使用Python爬虫技术合法合规地获取1688接口数…...
生成树协议STP工作步骤
第一步:选择根桥 优先级比较:首先比较优先级,优先级值越小的是根桥MAC地址比较:如果优先级相同,则比较MAC地址。MAC地址小的是根桥。 MAC地址比较的时候从左往右,一位一位去比 第二步:所有非根…...
Android14 AOSP支持短按关机
修改frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java diff --git a/base/services/core/java/com/android/server/policy/PhoneWindowManager.java b/base/services/core/java/com/android/server/policy/PhoneWindowManager.java in…...
C# 和 go 关于can通信得 整理
在C#中开发CAN(Controller Area Network)通信接口时,确实有一些现成的NuGet包可以简化你的开发工作。这些库通常提供了与CAN硬件接口通信所需的基本功能,如发送和接收CAN消息。下面是一些常用的NuGet包: PCANBasic.NET…...
设计模式和设计原则回顾
设计模式和设计原则回顾 23种设计模式是设计原则的完美体现,设计原则设计原则是设计模式的理论基石, 设计模式 在经典的设计模式分类中(如《设计模式:可复用面向对象软件的基础》一书中),总共有23种设计模式,分为三大类: 一、创建型模式(5种) 1. 单例模式(Sing…...
椭圆曲线密码学(ECC)
一、ECC算法概述 椭圆曲线密码学(Elliptic Curve Cryptography)是基于椭圆曲线数学理论的公钥密码系统,由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA,ECC在相同安全强度下密钥更短(256位ECC ≈ 3072位RSA…...
QMC5883L的驱动
简介 本篇文章的代码已经上传到了github上面,开源代码 作为一个电子罗盘模块,我们可以通过I2C从中获取偏航角yaw,相对于六轴陀螺仪的yaw,qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...
理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端
🌟 什么是 MCP? 模型控制协议 (MCP) 是一种创新的协议,旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议,它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...
AtCoder 第409场初级竞赛 A~E题解
A Conflict 【题目链接】 原题链接:A - Conflict 【考点】 枚举 【题目大意】 找到是否有两人都想要的物品。 【解析】 遍历两端字符串,只有在同时为 o 时输出 Yes 并结束程序,否则输出 No。 【难度】 GESP三级 【代码参考】 #i…...
基于Docker Compose部署Java微服务项目
一. 创建根项目 根项目(父项目)主要用于依赖管理 一些需要注意的点: 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件,否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...
微信小程序云开发平台MySQL的连接方式
注:微信小程序云开发平台指的是腾讯云开发 先给结论:微信小程序云开发平台的MySQL,无法通过获取数据库连接信息的方式进行连接,连接只能通过云开发的SDK连接,具体要参考官方文档: 为什么? 因为…...
使用 SymPy 进行向量和矩阵的高级操作
在科学计算和工程领域,向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能,能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作,并通过具体…...
springboot整合VUE之在线教育管理系统简介
可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生,小白用户,想学习知识的 有点基础,想要通过项…...
Rust 开发环境搭建
环境搭建 1、开发工具RustRover 或者vs code 2、Cygwin64 安装 https://cygwin.com/install.html 在工具终端执行: rustup toolchain install stable-x86_64-pc-windows-gnu rustup default stable-x86_64-pc-windows-gnu 2、Hello World fn main() { println…...
