PMTUD By UDP
通过UDP探测MTU,并实现udp echo server
// Description: UDP echo server.
// g++ udp_echo_server.cc -o udp_echo_server
#include <iostream>
#include <cstring>
#include <arpa/inet.h>
#include <unistd.h>#define PORT 12345
#define BUFFER_SIZE 4096
#define IPV4_HEADER_SIZE 20
#define UDP_HEADER_SIZE 8int main() {int sockfd;char buffer[BUFFER_SIZE];struct sockaddr_in servaddr, cliaddr;socklen_t len;// 创建UDP套接字sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (sockfd < 0) {std::cerr << "Socket creation failed" << std::endl;return 1;}// 设置不分片选项int dontfrag = IP_PMTUDISC_DO;if (setsockopt(sockfd, IPPROTO_IP, IP_MTU_DISCOVER, &dontfrag, sizeof(dontfrag)) < 0) {std::cerr << "Failed to set IP_MTU_DISCOVER option" << std::endl;close(sockfd);return 1;}// 清空地址结构memset(&servaddr, 0, sizeof(servaddr));memset(&cliaddr, 0, sizeof(cliaddr));// 填充服务器信息servaddr.sin_family = AF_INET;servaddr.sin_addr.s_addr = htonl(INADDR_ANY);servaddr.sin_port = htons(PORT);// 绑定套接字到指定端口if (bind(sockfd, (const struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) {std::cerr << "Bind failed" << std::endl;close(sockfd);return 1;}std::cout << "UDP echo server started, listening on port " << PORT << "..." << std::endl;while (true) {len = sizeof(cliaddr);// 接收数据int n = recvfrom(sockfd, buffer, BUFFER_SIZE, 0, (struct sockaddr *)&cliaddr, &len);if (n > 0) {buffer[n] = '\0';char host_buffer[INET_ADDRSTRLEN];inet_ntop(AF_INET, &cliaddr.sin_addr, host_buffer, INET_ADDRSTRLEN);printf("RX from [%s:%u] -> %d B, mtu = %d\n", host_buffer, ntohs(cliaddr.sin_port), n, n + IPV4_HEADER_SIZE + UDP_HEADER_SIZE);// 发送回显数据sendto(sockfd, buffer, n, 0, (const struct sockaddr *)&cliaddr, len);} else {perror("recvfrom");}}close(sockfd);return 0;
}
// Description: UDP echo client with path MTU discovery.
// g++ udp_echo_client.cc -o udp_echo_client
#include <iostream>
#include <cstring>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>#define SERVER_PORT 12345
#define BUFFER_SIZE 65536#define IPV4_HEADER_SIZE 20
#define UDP_HEADER_SIZE 8int discover_path_mtu(const struct sockaddr_in &servaddr)
{int sockfd;char probe_packet[BUFFER_SIZE];int32_t mtu_lbound, mtu_current, mtu_ubound, mtu_best;mtu_best = 68;mtu_lbound = 68;mtu_ubound = 65535;struct sockaddr_in remote_host;// 创建UDP套接字sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (sockfd < 0) {std::cerr << "Socket creation failed" << std::endl;return -1;}// 设置不分片选项int dontfrag = IP_PMTUDISC_DO;if (setsockopt(sockfd, IPPROTO_IP, IP_MTU_DISCOVER, &dontfrag, sizeof(dontfrag)) < 0) {std::cerr << "Failed to set IP_MTU_DISCOVER option" << std::endl;close(sockfd);return -1;}struct timeval timeout;timeout.tv_sec = 0;timeout.tv_usec = 500000; // 500msif (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout)) != 0) {perror("Error in setsockopt(timeout/udp)");return -1;}while (mtu_lbound <= mtu_ubound) {mtu_current = (mtu_lbound + mtu_ubound) / 2;memset(probe_packet, 'a', mtu_current - IPV4_HEADER_SIZE - UDP_HEADER_SIZE); // 减去IPv4头(20字节)和UDP头(8字节)probe_packet[mtu_current - IPV4_HEADER_SIZE - UDP_HEADER_SIZE] = '\0';// 发送探测数据包int bytes = sendto(sockfd, probe_packet, mtu_current - IPV4_HEADER_SIZE - UDP_HEADER_SIZE, 0, (const struct sockaddr *)&servaddr, sizeof(servaddr));if (bytes < 0) {if (errno == EMSGSIZE) {printf("packet(%d) [%d, %d] too big for local interface\n", mtu_current, mtu_lbound, mtu_ubound);mtu_ubound = mtu_current - 1; // update rangecontinue;}perror("Error in sendto()");return -1;}char buffer[BUFFER_SIZE] = {0};socklen_t len = sizeof(remote_host);bytes = recvfrom(sockfd, buffer, BUFFER_SIZE, 0, (struct sockaddr *)&remote_host, &len);if (bytes < 0) {// timeoutif (errno == EAGAIN || errno == EWOULDBLOCK) {printf("timeout\n");mtu_ubound = mtu_current - 1;continue;}perror("Error in recvfrom()");return -1;} else if (bytes > 0) {printf("mtu = %d [%d, %d]\n", bytes + IPV4_HEADER_SIZE + UDP_HEADER_SIZE, mtu_lbound, mtu_ubound);if (strncmp(probe_packet, buffer, bytes) == 0) {mtu_lbound = mtu_current + 1;} else {mtu_ubound = mtu_current - 1;}if (mtu_current > mtu_best) {mtu_best = mtu_current;}} else {printf("recvfrom() returned 0\n");return -1;}}close(sockfd);std::cout << "The MTU of the path is: " << mtu_best << " B" << std::endl;return mtu_best;
}int main(int argc, char* argv[])
{int opt;const char *server_address = "127.0.0.1";int32_t port = SERVER_PORT;while ((opt = getopt(argc, argv, "s:p:")) != -1) {switch (opt) {case 's':server_address = optarg;break;case 'p':port = atoi(optarg);break;default: /* '?' */fprintf(stderr, "Usage: %s -s server_address -p port\n", argv[0]);return 0;}}// 解析服务器地址struct hostent* host = gethostbyname(server_address);if (host == nullptr) {std::cerr << "Failed to resolve hostname: " << server_address << std::endl;return 1;}int sockfd;char buffer[BUFFER_SIZE];struct sockaddr_in servaddr;// 创建UDP套接字sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (sockfd < 0) {std::cerr << "Socket creation failed" << std::endl;return 1;}// 设置不分片选项int dontfrag = IP_PMTUDISC_DO;if (setsockopt(sockfd, IPPROTO_IP, IP_MTU_DISCOVER, &dontfrag, sizeof(dontfrag)) < 0) {std::cerr << "Failed to set IP_MTU_DISCOVER option" << std::endl;close(sockfd);return -1;}// 清空服务器地址结构memset(&servaddr, 0, sizeof(servaddr));// 填充服务器信息servaddr.sin_family = AF_INET;servaddr.sin_port = htons(port);memcpy(&servaddr.sin_addr, host->h_addr, host->h_length);// 探测路径MTUint mtu = discover_path_mtu(servaddr);if (mtu <= 0) {std::cerr << "Path MTU detection failed" << std::endl;}while (true) {std::cout << "Please enter the data to be sent:";std::string message;std::getline(std::cin, message);if (message.empty()) {break;}// 发送数据sendto(sockfd, message.c_str(), message.size(), 0, (const struct sockaddr *)&servaddr, sizeof(servaddr));// 接收回显数据socklen_t len = sizeof(servaddr);int n = recvfrom(sockfd, buffer, BUFFER_SIZE, 0, (struct sockaddr *)&servaddr, &len);buffer[n] = '\0';std::cout << "RX:" << buffer << std::endl;}close(sockfd);return 0;
}
相关文章:
PMTUD By UDP
通过UDP探测MTU,并实现udp echo server // Description: UDP echo server. // g udp_echo_server.cc -o udp_echo_server #include <iostream> #include <cstring> #include <arpa/inet.h> #include <unistd.h>#define PORT …...
Hutool - BloomFilter:便捷的布隆过滤器实现
1. 布隆过滤器简介 布隆过滤器(Bloom Filter)是一种空间效率极高的概率型数据结构,用于判断一个元素是否存在于一个集合中。它的优点是空间效率和查询时间都远远超过一般的算法,但缺点是有一定的误判率,即判断元素存在…...

【学习资源】时间序列数据分析方法(1)
时间序列数据分析是一个有趣的话题,让我们多花一些时间来研究。此篇为第一篇文章。主要介绍特征提取方法、深度学习时序数据分析模型、参考资源。期望能帮助大家解决工业领域的相关问题。 1 特征提取方法:信号处理 (来源:INTELLIGENT FAULT DIAGNOSIS A…...

盛铂科技SWFA100捷变频频率综合器:高性能国产射频系统的关键选择
在现代射频系统中,频率综合器是实现精确频率控制和快速跳频的核心组件。盛铂科技推出的SWFA100捷变频频率综合器凭借其卓越的性能和小型化设计,成为高性能射频系统中的理想选择。 SWFA100捷变频频率综合器 高速跳频与宽频覆盖 SWFA100捷变频频率综合器能…...

释放你的元数据:使用 Elasticsearch 的自查询检索器
作者:来自 Elastic Josh Asres 了解如何使用 Elasticsearch 的 “self-quering” 检索器来通过结构化过滤器提高语义搜索的相关性。 在人工智能搜索的世界中,在海量的数据集中高效地找到正确的数据至关重要。传统的基于关键词的搜索在处理涉及自然语言的…...

【快速幂算法】快速幂算法讲解及C语言实现(递归实现和非递归实现,附代码)
快速幂算法 快速幂算法可用分治法实现 不难看出,对任意实数a和非负整数n,有: a n { 1 , n 0 , a ≠ 0 0 , a 0 ( a n 2 ) 2 , n > 0 , n 为偶数 ( a n 2 ) 2 ∗ a , n > 0 , n 为奇数 a^n \begin{cases} 1, & n 0, a\neq 0…...

3. 导入官方dashboard
官方dashboard:https://grafana.com/grafana/dashboards 1. 点击仪表板 - 新建 - 导入 注:有网络的情况想可以使用ID,无网络情况下使用仪表板josn文件 2. 在官方dashboard网页上选择符合你现在数据源的dashboard - 点击进入 3. 下拉网页选…...

怎么理解 Spring Boot 的约定优于配置 ?
在传统的 Spring 开发中,大家可能都有过这样的经历:项目还没开始写几行核心业务代码,就已经在各种配置文件中耗费了大量时间。比如,要配置数据库连接,不仅要在 XML 文件里编写冗长的数据源配置,还要处理事务…...
Dify 是什么?Dify是一个开源的LLM应用开发平台,支持快速搭建生成式AI应用,具有RAG管道、Agent功能、模型集成等特点
首先,Dify是一个开源的LLM应用开发平台,支持快速搭建生成式AI应用,具有RAG管道、Agent功能、模型集成等特点75。根据搜索结果,网页6详细对比了多个RAG和AI开发框架,包括MaxKB、FastGPT、RagFlow、Anything-LLM等。其中…...

数据预处理都做什么,用什么工具
数据预处理是数据分析、数据挖掘和机器学习中的关键步骤,其目的是将原始数据转换为适合后续分析或建模的格式。以下是关于数据预处理的主要内容及常用工具的详细介绍: 一、数据预处理的主要任务 数据预处理的主要任务包括以下几个方面: 数据…...
windows蓝牙驱动开发-在蓝牙配置文件驱动程序中接受 L2CAP 连接
L2CAP 服务器配置文件驱动程序会响应来自远程设备的传入逻辑链接控制和适应协议 (L2CAP) 连接请求。 例如,PDA 的 L2CAP 服务器配置文件驱动程序将响应来自 PDA 的传入连接请求。 接收传入 L2CAP 连接请求 1. 若要接收来自特定 PSM 的任何远程设备的传入 L2CAP 连…...

【原理图PCB专题】自制汉字转码工具,适配Allgero 17版本 Skill
众所周知,在使用Skill来编写Allegro控制脚本时如果程序的源码里是汉字,那么有可能会出现乱码。比如像下图这样的程序: 在Allegro中运行如下图所示: 那么如果我们需要让他转成正常的中文字符,就需要将字符转成GBK编码 打开自制小软件:中文与GBK编码互转V1…...
欧拉公式在信号处理中的魔法:调幅信号的生成与频谱分析
欧拉公式在信号处理中的魔法:调幅信号的生成与频谱分析 “数学不是枯燥的符号,而是宇宙的诗歌。” 当我们用欧拉公式解开调幅信号的频谱密码时,仿佛看到电磁波在时空中跳动的频率之舞。这篇博客将带你亲手触摸信号处理中的数学之美。 一、当欧拉公式遇见调幅信号:一场数学与…...
如何在Ubuntu中切换多个PHP版本
在Ubuntu环境下实现PHP版本的灵活切换,是众多开发者与系统管理员的重要技能之一。下面,我们将深入探讨如何在Ubuntu系统中安装、配置及管理多个PHP版本,确保您的开发环境随心所欲地适应各类项目需求。 开始前的准备 确保您的Ubuntu系统保持…...
基于opencv的HOG+角点匹配教程
1. 引言 在计算机视觉任务中,特征匹配是目标识别、图像配准和物体跟踪的重要组成部分。本文介绍如何使用 HOG(Histogram of Oriented Gradients,方向梯度直方图) 和 角点检测(Corner Detection) 进行特征匹…...

Linux线程概念与线程操作
Linux线程概念与线程操作 线程概念 前面提到进程程序代码和数据进程结构体,在线程部分就需要进一步更新之前的认识 进程实际上承担分配系统资源的基本实体,而线程是进程中的一个执行分支,是操作系统调度的基本单位 此处需要注意࿰…...
AI软件栈:LLVM分析(五)
数据流分析是编译优化、代码生成的关键理论。其数学基础是离散数学中的半格(Semi-Lattice)和格。半格与格不仅是编译优化和代码生成的重要理论基础,也是程序分析、验证及自动化测试的系统理论基础。 文章目录 格、半格与不动点格、半格与不动点 半格是指针对二元组 < S …...

Git指南-从入门到精通
代码提交和同步命令 流程图如下: 第零步: 工作区与仓库保持一致第一步: 文件增删改,变为已修改状态第二步: git add ,变为已暂存状态 bash $ git status $ git add --all # 当前项目下的所有更改 $ git add . # 当前目录下的所有更改 $ g…...

Linux 文件系统挂载
系列文章目录 Linux内核学习 Linux 知识(1) Linux 知识(2) WSL Ubuntu QEMU 虚拟机 Linux 调试视频 PCIe 与 USB 的补充知识 vscode 使用说明 树莓派 4B 指南 设备驱动畅想 Linux内核子系统 Linux 文件系统挂载 文章目录 系列文章…...
Qt QSpinBox 总结
Qt5 QSpinBox 总结 1. 基本特性 用途:用于输入和调整整数值,支持通过上下箭头、键盘输入或编程方式修改值。 默认范围:0 到 99,可通过 setRange(min, max) 自定义。 步长控制:setSingleStep(step) 设置单步增减值&a…...
内存分配函数malloc kmalloc vmalloc
内存分配函数malloc kmalloc vmalloc malloc实现步骤: 1)请求大小调整:首先,malloc 需要调整用户请求的大小,以适应内部数据结构(例如,可能需要存储额外的元数据)。通常,这包括对齐调整,确保分配的内存地址满足特定硬件要求(如对齐到8字节或16字节边界)。 2)空闲…...

智慧医疗能源事业线深度画像分析(上)
引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...

docker详细操作--未完待续
docker介绍 docker官网: Docker:加速容器应用程序开发 harbor官网:Harbor - Harbor 中文 使用docker加速器: Docker镜像极速下载服务 - 毫秒镜像 是什么 Docker 是一种开源的容器化平台,用于将应用程序及其依赖项(如库、运行时环…...

基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真
目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销,平衡网络负载,延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...

【Oracle APEX开发小技巧12】
有如下需求: 有一个问题反馈页面,要实现在apex页面展示能直观看到反馈时间超过7天未处理的数据,方便管理员及时处理反馈。 我的方法:直接将逻辑写在SQL中,这样可以直接在页面展示 完整代码: SELECTSF.FE…...

Zustand 状态管理库:极简而强大的解决方案
Zustand 是一个轻量级、快速和可扩展的状态管理库,特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...

安宝特方案丨XRSOP人员作业标准化管理平台:AR智慧点检验收套件
在选煤厂、化工厂、钢铁厂等过程生产型企业,其生产设备的运行效率和非计划停机对工业制造效益有较大影响。 随着企业自动化和智能化建设的推进,需提前预防假检、错检、漏检,推动智慧生产运维系统数据的流动和现场赋能应用。同时,…...
可靠性+灵活性:电力载波技术在楼宇自控中的核心价值
可靠性灵活性:电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中,电力载波技术(PLC)凭借其独特的优势,正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据,无需额外布…...

《通信之道——从微积分到 5G》读书总结
第1章 绪 论 1.1 这是一本什么样的书 通信技术,说到底就是数学。 那些最基础、最本质的部分。 1.2 什么是通信 通信 发送方 接收方 承载信息的信号 解调出其中承载的信息 信息在发送方那里被加工成信号(调制) 把信息从信号中抽取出来&am…...

12.找到字符串中所有字母异位词
🧠 题目解析 题目描述: 给定两个字符串 s 和 p,找出 s 中所有 p 的字母异位词的起始索引。 返回的答案以数组形式表示。 字母异位词定义: 若两个字符串包含的字符种类和出现次数完全相同,顺序无所谓,则互为…...