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…...
从键盘到5G模组:深入浅出聊聊USB那些五花八门的‘设备类’(HID/CDC/MSC)
从键盘到5G模组:深入浅出聊聊USB那些五花八门的‘设备类’(HID/CDC/MSC) 当你在键盘上敲下字符、用U盘拷贝文件,或是通过4G模块联网时,背后都有一群看不见的"协议翻译官"在忙碌——它们就是USB设备类&#x…...
从DataFrame到MySQL:利用pandas与pymysql实现高效数据迁移
1. 为什么需要把DataFrame数据写入MySQL? 在日常数据分析工作中,我们经常使用pandas处理数据。DataFrame作为pandas的核心数据结构,提供了丰富的数据操作功能。但分析结果最终需要持久化存储时,MySQL这类关系型数据库仍然是企业级…...
轻量级日志聚合器Shiplog:中小团队分布式日志管理实践
1. 项目概述:一个为开发者打造的轻量级日志聚合器如果你是一名后端开发者,或者正在维护一个分布式微服务系统,那么对“日志”这个词一定又爱又恨。爱的是,它是排查线上问题的唯一“时光机”;恨的是,当服务实…...
系统发育树可视化终极指南:用TreeViewer轻松创建专业级进化树
系统发育树可视化终极指南:用TreeViewer轻松创建专业级进化树 【免费下载链接】TreeViewer Cross-platform software to draw phylogenetic trees 项目地址: https://gitcode.com/gh_mirrors/tr/TreeViewer 你是否曾为系统发育树的可视化而烦恼?面…...
2025届必备的六大AI科研方案推荐
Ai论文网站排名(开题报告、文献综述、降aigc率、降重综合对比) TOP1. 千笔AI TOP2. aipasspaper TOP3. 清北论文 TOP4. 豆包 TOP5. kimi TOP6. deepseek 从文本特征着手,才能降低人工智能生成内容被检出的概率。首先,要融入…...
Zotero PDF Translate终极配置指南:如何一键激活20+翻译服务
Zotero PDF Translate终极配置指南:如何一键激活20翻译服务 【免费下载链接】zotero-pdf-translate Translate PDF, EPub, webpage, metadata, annotations, notes to the target language. Support 20 translate services. 项目地址: https://gitcode.com/gh_mir…...
Markdown基础功能
原文:Markdown基础语法介绍 | Colin Gretzky的博客 本文介绍 Markdown 笔记格式的基础功能,涵盖核心语法和使用要点,适合初学者快速上手。 Markdown 简介 Markdown 是一种轻量级的标记语言,由 John Gruber 于 2004 年设计。它的核…...
人工智能-现代方法(一)
2026.05.12 这几天开始看《人工智能-现代方法》,做一些知识记录。 1、学习的概念:归纳和演绎。(19章) 演绎靠逻辑推理,归纳靠经验总结。所以在前提正确的情况下,演绎的结论必然正确。归纳的结论则有可能出现…...
基于本地大模型与Playwright的隐私优先求职自动化助手RedClaw实践
1. 项目概述:一个真正为你掌控的本地化求职AI助手在求职季,我们常常面临一个两难困境:一方面,海投简历耗时耗力,重复填写那些大同小异的在线申请表让人筋疲力尽;另一方面,市面上一些所谓的“自动…...
嵌入式开发中的编程规范实践与行业标准解析
1. 编程规范的本质与价值在嵌入式汽车电子领域干了十五年,我见过太多因为代码不规范导致的惨痛教训。有一次,某车企的ECU控制模块在零下30度环境突然死机,排查三周后发现是未初始化的指针在低温环境下产生了非预期行为——这种问题本可以通过…...
