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…...
java_网络服务相关_gateway_nacos_feign区别联系
1. spring-cloud-starter-gateway 作用:作为微服务架构的网关,统一入口,处理所有外部请求。 核心能力: 路由转发(基于路径、服务名等)过滤器(鉴权、限流、日志、Header 处理)支持负…...
centos 7 部署awstats 网站访问检测
一、基础环境准备(两种安装方式都要做) bash # 安装必要依赖 yum install -y httpd perl mod_perl perl-Time-HiRes perl-DateTime systemctl enable httpd # 设置 Apache 开机自启 systemctl start httpd # 启动 Apache二、安装 AWStats࿰…...
深入理解JavaScript设计模式之单例模式
目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式(Singleton Pattern&#…...
今日科技热点速览
🔥 今日科技热点速览 🎮 任天堂Switch 2 正式发售 任天堂新一代游戏主机 Switch 2 今日正式上线发售,主打更强图形性能与沉浸式体验,支持多模态交互,受到全球玩家热捧 。 🤖 人工智能持续突破 DeepSeek-R1&…...
select、poll、epoll 与 Reactor 模式
在高并发网络编程领域,高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表,以及基于它们实现的 Reactor 模式,为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。 一、I…...
2023赣州旅游投资集团
单选题 1.“不登高山,不知天之高也;不临深溪,不知地之厚也。”这句话说明_____。 A、人的意识具有创造性 B、人的认识是独立于实践之外的 C、实践在认识过程中具有决定作用 D、人的一切知识都是从直接经验中获得的 参考答案: C 本题解…...
docker 部署发现spring.profiles.active 问题
报错: org.springframework.boot.context.config.InvalidConfigDataPropertyException: Property spring.profiles.active imported from location class path resource [application-test.yml] is invalid in a profile specific resource [origin: class path re…...
Java线上CPU飙高问题排查全指南
一、引言 在Java应用的线上运行环境中,CPU飙高是一个常见且棘手的性能问题。当系统出现CPU飙高时,通常会导致应用响应缓慢,甚至服务不可用,严重影响用户体验和业务运行。因此,掌握一套科学有效的CPU飙高问题排查方法&…...
rnn判断string中第一次出现a的下标
# coding:utf8 import torch import torch.nn as nn import numpy as np import random import json""" 基于pytorch的网络编写 实现一个RNN网络完成多分类任务 判断字符 a 第一次出现在字符串中的位置 """class TorchModel(nn.Module):def __in…...
Hive 存储格式深度解析:从 TextFile 到 ORC,如何选对数据存储方案?
在大数据处理领域,Hive 作为 Hadoop 生态中重要的数据仓库工具,其存储格式的选择直接影响数据存储成本、查询效率和计算资源消耗。面对 TextFile、SequenceFile、Parquet、RCFile、ORC 等多种存储格式,很多开发者常常陷入选择困境。本文将从底…...
