UDP数据包的延迟及丢包检测(C++)

2023-05-16

摘要

本文记录通过数据报套接字来检测UDP数据包的延迟和丢包的思路和简单的代码实现。

思路

UDP协议及用户数据报协议在传输层提供了无连接、不可靠的传输服务,端到端的延迟以及丢包率是反应当前网络环境好坏的重要评价标准。Ping检测延迟的方式是:发送端发送一个ICMP包给接收端,接收端接收到ICMP包之后向发送端回应一个包,发送端可以计算出往返时间(RTT),本文通过套接字使用类似于Ping的思路来计算RTT来反映延迟的大小,可以多次发包根据多次的结果来计算一个平均的RTT;丢包率可以通过指定发送端发包的数量,然后在接收端统计接收成功的数量,就可以计算出当前丢包率。

说明

  • 数据报套接字(SOCK-DGRAM)在传输层使用的UDP协议,所以在创建socket的时候一定要指定使用SOCK_DGRAM类型的套接字,这样系统在封装数据包的时候才使用的是UDP协议。
  • 因为不同设备的网络数据发送能力和接受能力都有限,发送端每次发送内容的长度也就是数据包的大小,以及发送速率都是影响接收端延迟和丢包率的因素;因此将发送数据大小(bytes)、发送数据包数量、发送间隔(ms)都作为程序的参数,根据不用的应用场景指定对应的参数,得到的结果会有一定的参考价值。

代码实现

加入头文件

代码实在windows环境下写的,所以发送端和接收端调用函数之前都需要加入头文件和预处理指令

#include <iostream>
#include <ctime>
#include <winsock2.h>
#pragma comment (lib, "ws2_32.lib")  //加载 ws2_32.dll

发送端函数

//参数分别为接收端的IP地址、端口以及本次发包的数量和每个包的内容长度
void udp_delay_detect_client(const char* ip,int port,int packetSize,int packetNum)
{
	WSADATA wsaData;
    WSAStartup(MAKEWORD(2, 2), &wsaData);
    //创建UDP套接字
    SOCKET sock = socket(PF_INET, SOCK_DGRAM, 0);

    //服务器地址信息
    sockaddr_in servAddr;
    memset(&servAddr, 0, sizeof(servAddr));  //每个字节都用0填充
    servAddr.sin_family = PF_INET;
    servAddr.sin_addr.s_addr = inet_addr(ip);
    servAddr.sin_port = htons(port);
    //不断获取用户输入并发送给服务器,然后接受服务器数据
    SOCKADDR clntAddr;  //客户端地址信息
    int nSize = sizeof(SOCKADDR);
    char bufSend[packetSize+1];
    memset(bufSend,'a',sizeof(bufSend));
    bufSend[packetSize]='\0';

    char bufRecv[packetSize+1];
	//先发一个包告诉接收端要开始发包了
    sendto(sock,bufSend,strlen(bufSend),0,(struct sockaddr*)&servAddr, sizeof(servAddr));		

    int send_count=packetNum;
    int recv_count=0;

    double sum_delay=0;
    double sum_jitter=0;
    double last_delay;

    int recv_miss_count=0;

    //设置超时等待
    int timeout = 2000; //2s
    int ret=setsockopt(sock,SOL_SOCKET,SO_RCVTIMEO,(char*)&timeout,sizeof(timeout));

    while(send_count--){
        sendto(sock, bufSend, strlen(bufSend), 0, (struct sockaddr*)&servAddr, sizeof(servAddr));
        clock_t start=clock();
        int strLen = recvfrom(sock, bufRecv, packetSize, 0, &clntAddr, &nSize);
        if(strLen<1)
        {
            continue;
        }
        clock_t end=clock();
        recv_count++;
        double delay=(double)(end-start)*1000/CLOCKS_PER_SEC;
        double jitter;
        if(send_count==packetNum){jitter=0,last_delay=delay;continue;}
        jitter=fabs(delay-last_delay);
        sum_delay+=delay;
        sum_jitter+=jitter;
    }

    double delay=sum_delay/packetNum;
    double jitter=sum_jitter/packetNum;
    cout<<"RRT:"<<delay<<"ms jitter:"<<jitter<<"ms packet_loss_rate:"<<1-(double)recv_count/packetNum<<endl;
    closesocket(sock);
}

接收端函数
void udp_delay_detect_server(int port)		//指定端口
{
	WSADATA wsaData;
    WSAStartup(MAKEWORD(2, 2), &wsaData);
    //创建套接字
    SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0);
    //绑定套接字
    sockaddr_in servAddr;
    memset(&servAddr, 0, sizeof(servAddr));  //每个字节都用0填充
    servAddr.sin_family = PF_INET;  //使用IPv4地址
    servAddr.sin_addr.s_addr = htonl(INADDR_ANY); //自动获取IP地址
    servAddr.sin_port = htons(port);  //端口
    bind(sock, (SOCKADDR*)&servAddr, sizeof(SOCKADDR));
    //接收客户端请求
    SOCKADDR clntAddr;  //客户端地址信息
    int nSize = sizeof(SOCKADDR);
    char buffer[BUF_SIZE];  //缓冲区
    
    recvfrom(sock,buffer,BUF_SIZE,0,&clntAddr,&nSize);			//接受发送端的开始发送的信号
    
    int recv_count=0;
    //设置超时等待
    int timeout = 2000; //2s
    int ret=setsockopt(sock,SOL_SOCKET,SO_RCVTIMEO,(char*)&timeout,sizeof(timeout));

    int recv_miss_count=0;
    while(1){
        int strLen = recvfrom(sock, buffer, BUF_SIZE, 0, &clntAddr, &nSize);
        if(strLen>1)              //验证接受字符串的长度
        {
            sendto(sock, buffer, strLen, 0, &clntAddr, nSize);
            recv_count++;
        }
        else{
            recv_miss_count++;
            cout<<"no packet recieve!"<<endl;
            if(recv_miss_count==3)				//超过三次超时等待则认为接收完毕
                break;
        }
    }
    cout<<"packet_recv_count:"<<recv_count<<endl;
    closesocket(sock);
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

UDP数据包的延迟及丢包检测(C++) 的相关文章

  • 播放 UDP 数据包中收到的原始 PCM 音频

    远程设备正在 UDP 数据包中发送实时原始 PCM 音频 不包含标头 我需要在 java 中实现一个程序来接收这些数据包并在 PC 上实时播放它们 据我所知 原始 PCM 的属性是 16 位 单声道 采样率 24KHz 因此我尝试向该原始
  • 如何使用 ZeroMQ 处理原始 UDP?

    我有一个客户 我无法更改其代码 但我想使用 重新 编写ZeroMQ插座 客户使用原始TCP和原始的UDP插座 我知道我可以使用ZMQ ROUTER RAW对于生的TCP插座 但是原始的怎么样 UDP数据流 ZeroMQ 中对 UDP 的支持
  • UdpClient 在广播地址上接收

    在 c 中 我使用 UdpClient Receive 函数 public void StartUdpListener Object state try udpServer new UdpClient new IPEndPoint IPAd
  • Java:使用多个 DatagramSocket 接收 UDP 数据报包

    我正在尝试实现一种将 UDP 数据包发送到多个接收者的方法 我认为这应该是可行的设置setReuseAddress true 在接收 DatagramSocket 实例上 我的问题是 在某些情况下 我需要限制与本地计算机的通信 因此限制本地
  • C++ 反序列化通过 UDP 从 C# 应用程序发送的对象

    我有一个申请c 它连接到另一个应用程序 编写为c 通过UDP 我更喜欢高性能的解决方案 因为我希望测量事件客户端 某些处理服务器端和客户端处理完成的响应之间的时间 本质上是 往返延迟 我有一个 C 对象 例如 public class Pa
  • 通过 Internet 发送 UDP 数据包

    我正在尝试了解 P2P 去中心化网络的一些细节 我的问题如下 假设我有两台名为 comp1 和 comp2 的机器 现在 comp1 设置在我的家庭网络中的路由器后面 comp2 位于我的办公室中 也位于路由器后面 我是否可以像这样在 In
  • 什么是消息边界?

    什么是 消息边界 在以下情况下 TCP 和 UDP 之间的区别之一是 UDP 保留消息 边界 我理解之间的区别TCP and UDP 但我不确定的定义 消息边界 由于 UDP 在每个单独的数据包中包含目的地和端口信息 因此是否可以为消息提供
  • netty 4.x.x 中的 UDP 广播

    我们需要使用 Netty 4 0 0 二进制文件通过 UDP 通道广播对象 Pojo 在 Netty 4 0 0 中 它允许我们仅使用 DatagramPacket 类来发送 UDP 数据包 此类仅接受 ByteBuf 作为参数 还有其他方
  • 在 Perl 中如何接受多个 TCP 连接?

    我对 Linux 的 Perl 脚本有疑问 它的主要目的是成为 3 个应用程序之间的中间人 它应该做什么 它应该能够等待 UDP 文本 不带空格 udp port 当它收到 UDP 文本时 它应该将其转发到连接的 TCP 客户端 问题是我的
  • 为什么通过UdpClient发送会导致后续接收失败?

    我正在尝试创建一个 UDP 服务器 它可以向所有向其发送消息的客户端发送消息 真实情况要复杂一些 但最简单的方法是将其想象为一个聊天服务器 之前发送过消息的每个人都会收到其他客户端发送的所有消息 所有这一切都是通过UdpClient 在单独
  • 自 2012 年以来,WinSock 注册 IO 性能是否有所下降?

    我最近使用 MS 为该 API 提供的稍微可接受的文档编写了基于 WinSock Registered IO RIO 的 UDP 接收 最终的性能非常令人失望 单套接字性能有些稳定 约为每秒 180k 数据包 使用多个 RSS 队列 即多个
  • 提高UDP可靠性

    我正在构建一个基于 UDP 的小型服务器 服务器基于 Net并使用它自己的Socket类 我通过 ReceiveMessageFromAsync 和异步发送使用完成端口 我的问题是我失去了大约 5 10 的流量 现在我明白这是正常的 但是有
  • 为多线程 UDP 客户端执行“close ()”时套接字描述符未释放

    我在下面编写了 UDP 客户端 它基本上生成一个单独的线程来接收数据报 但是数据报仅在主线程中发送 现在 在 Linux 发行版上实例化 udpClient 1 UDP 客户端后按 ctrl D 实现退出循环 围绕 getline 调用 并
  • 视频流上的 TCP 与 UDP

    我刚从网络编程考试回来 他们问我们的问题之一是 如果您要传输视频 您会使用 TCP 还是 UDP 请解释一下存储视频和实时视频流 对于这个问题 他们只是希望得到一个简短的答案 TCP 用于存储视频 UDP 用于实时视频 但我在回家的路上想到
  • UDP 广播发送失败:在 Linux 2.6.30 上“网络无法访问”

    我用udp广播写了一个程序 代码段如下 struct sockaddr in broadcast addr socklen t sock len sizeof broadcast addr bzero broadcast addr sock
  • Node.js 可读流_read用法

    我了解如何在 Node 的 new 中使用可写流Streams2库 但我不明白如何使用可读流 举个例子 一个流包装器围绕dgram module var dgram require dgram var thumbs twiddle func
  • 如何使用 Nmap 检索 TCP 和 UDP 端口? [关闭]

    Closed 这个问题是无关 help closed questions 目前不接受答案 我需要在使用 Nmap 的同一扫描中以尽可能最快的方式检索 TCP 和 UDP 端口 我会尽力解释得更好 如果我使用最常用的命令 nmap 192 1
  • 为什么SOCKS5需要通过UDP中继UDP?

    The SOCKS5 https en wikipedia org wiki SOCKS SOCKS5协议 描述为RFC1928 https www rfc editor org rfc rfc1928提供对 UDP 的支持 总而言之 希望
  • 尝试接收 UDP 多播时出现空指针异常

    在尝试了几次让简单的 UDP 多播接收器工作后 我感到很困惑 在我自己的代码无法按预期工作后 我尝试了 vertx 文档中发布的确切示例 DatagramSocket socket vertx createDatagramSocket ne
  • UDP接收和发送Matlab

    我目前正在努力从外部设备接收数据包 然后将数据发送到另一个设备 我有一个工作 Simulink 模型 但我不知道如何在 Matlab 中对其进行编码 Matlab 中 UDP 接收块的参数如下图所示UDP 接收参数 https i stac

随机推荐

  • jqgrid表格高度宽度设置

    jqgrid表格高度宽度设置 问题说明 gt 页面上使用上面搜索框 xff0c 下面是jqgrid表格形式 xff0c 总是出现 xff0c grid表格加载宽度 高度问题 本文通过主要解决表格高度宽度变化适应的问题 grid宽度 1 修改
  • 梯度下降法及matlab实现

    个人博客文章链接 xff1a http www huqj top article id 61 162 梯度下降法 xff08 gradient descent xff09 xff0c 是机器学习中最常用的参数调优算法 xff0c 所谓梯度下
  • 命令执行判断($?:命令回传值、&&、||)

    1 概述 当在linux中输入命令时 xff0c 命令可能成功也可能失败 xff0c 此时可以通过命令回传值来判断 xff08 符号 xff1a xff09 xff0c 命令回传值可以和 amp amp 与 一起使用 2 符号 amp am
  • LXC/KVM虚拟化基本概念

    1 LXC 其名称来自Linux软件容器 xff08 Linux Containers xff09 的缩写 一种操作系统层虚拟化 xff08 Operating system level virtualization xff09 技术 xf
  • 解决VNC连接安了Ubuntu MATE系统的树莓派3b时出现灰屏的问题

    1 xff09 首先安装vncserver服务 xff08 这一步有没有用我也不知道 xff0c 一般人都是装的tightvncserver 当然 xff0c 我也装了 xff09 sudo apt get install vnc4serv
  • Ubuntu18.04安装CUDA10、CUDNN

    上篇记录了Ubuntu下安装INVIDIA显卡驱动的方法 xff0c 尽管可以选择CUDA自带的驱动 xff0c 但为了避免不必要的问题 xff0c 尽量单独安装 如果没有单独安装驱动 xff0c 建议多找几篇博客 xff0c 对比来看 x
  • IDEA mavne项目转gradle项目

    文章目录 前言一 配置gradle二 将mavne项目转换为gradle1 找到项目根目录2 执行命令转换3 重启项目 配置IDEA 的 gradle4 转换后的样子 总结 前言 不知道小伙伴有没有遇到过这个问题 就是由于项目是用maven
  • 2016,再见 2017,还请多多指教

    先来一个象征意义上的序 今天是2017 01 01 新年的第一天 昨天适合总结 今天适合制作新年计划 昨天没做总结 于是今天总结和新年计划一起来吧 充满回忆的2016 昨天在驾校练车练了一天 倒库终于能倒进去了 回到住处已经下午5点 买了路
  • 3. 云计算的落地实践(下)

    本章讲解知识点 云计算如何落地实践 ISO镜像文件 创建虚拟机入门 创建数据节点 配置 VMWare创建虚拟机三种网络模式 1 云计算的落地实践 上一章我们讲了云计算的业界实践 即 搭建IaaS后 用于创建虚拟机 在虚拟机上部署PaaS 用
  • deepin15.8配置深度显卡驱动

    以deepin15 8为例 xff0c 电脑为联想的y7000 刚开始以网上下载 run文件的方式进行安装显卡驱动 xff0c 后来在下载cmake等一下工具的时候 xff0c 总会提示与显卡驱动某个模块版本冲突 xff0c 所以索性放弃了
  • 关于调用第三方接口时传递参数是File类型的解决方式

    最近在做一个项目 xff0c 需要频繁的调用第三方的接口 xff0c 本以为都是基本的数据类型 xff0c 没想到需要传一个文件类型的参数 xff0c 我想着调用接口的时候直接用文件流把文件写到connection不就行了 xff0c 这就
  • C#中?、?.、? ?、? ?=的用法和说明

    一 可空类型修饰符 xff1f 引用类型能用空引用来表示一个不存在的值 xff0c 但是值类型不能 例如 xff1a string str 61 null int i 61 null 编译报错 为了使值类型也能使用可空类型 xff0c 就可
  • TortorliseGit(小乌龟)创建删除(远程和本地)分支

    以下两篇文章分别为删除和创建 1 使用TortorliseGit 小乌龟 删除本地分支 xff0c 远程分支 2 使用TortoiseGit操作分支的创建与合并
  • UML类图的几种关系浅析

    类图中的主要关系有如下几种 关联关系 聚合关系 组合关系依赖关系泛化关系细化关系 注 xff1a 以下图片均来自网络 xff0c 侵删 1 关联关系 关联关系是类与类之间的连接 xff0c 表示一类对象与另一类对象之间有联系 xff0c 通
  • 关于c#创建界面的几种方式

    c 创建界面有很多种方式 xff0c 下面列举5中创建界面的方式 1 windows窗体 xff0c 这种窗体设计界面是最简单的一种 这种可以直接从工具箱拿出组件进行使用 xff0c 能够很好的设计界面 2 用户控件类 3 组件类 4 窗口
  • .ova文件转换成.ovf和.vmdk格式

    一 准备工具 xff1a 下载软件 xff1a OVFTool x64 下载地址 xff1a https pan baidu com s 1YDtHh0 OnK0Lm5C4KoF4 w 二 安装后 xff0c 去安装路径下 xff0c 按住
  • 【Word】如何在数学公式同一行末尾填写编号

    使用word插入公式框后 xff0c 在公式框中打完公式的末尾处 xff08 依旧在框内 xff09 加上 xff08 编号 xff09 xff0c 然后回车即可 xff01 xff01 超神器 xff01 再也不用手动空格啦 输入公式序号
  • 使用Xmanager软件远程调用图形化(可视化)安装Oracle数据库

    安装Oracle xff0c 使用调用图形化界面进行安装 xff0c 此次不能使用VNC远程到服务器本地进行图形化安装 xff0c 只能远程调用图形化进行本地安装 xff0c 方法如下 xff1a 一 Linux系统安装所需要的依赖组 xf
  • js中怎么删除对象的某个key值?js 遍历数组,有用!!

    参考 xff1a https blog csdn net denghaolinzy article details 87913561 formThead cate false id true out trade no true produc
  • UDP数据包的延迟及丢包检测(C++)

    摘要 本文记录通过数据报套接字来检测UDP数据包的延迟和丢包的思路和简单的代码实现 思路 UDP协议及用户数据报协议在传输层提供了无连接 不可靠的传输服务 xff0c 端到端的延迟以及丢包率是反应当前网络环境好坏的重要评价标准 Ping检测