当前位置: 首页 > news >正文

C/C++ 实现UDP发送或接收组播消息,并可指定接收发送网卡

一、发送端代码

#include <iostream>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/ioctl.h>
#include "UDPOperation.h"
#include "GlobalVariable.h"
#include "Logger.h"
#include "EndException.h"
#include "BaseException.h"UDPOperation::UDPOperation(char* remote_host, int remote_port, char* interface) : fd(-1)
{// 创建通信的套接字this->remote_host = remote_host;this->remote_port = remote_port;this->interface = interface;memset(&(this->cliaddr), 0, sizeof(sockaddr_in));this->cliaddr.sin_family = AF_INET;this->cliaddr.sin_port = htons(this->remote_port); // 接收端需要绑定remote_port端口
}UDPOperation::~UDPOperation() {}bool UDPOperation::create_udpsocket()
{this->fd = socket(AF_INET, SOCK_DGRAM, 0);if (this->fd == -1){LOG_ERROR("Socket creation failed: %s", strerror(errno));throw EndException(errno, strerror(errno));}inet_pton(AF_INET, this->remote_host, &this->cliaddr.sin_addr.s_addr);hostent* host = gethostbyname(remote_host);unsigned long hostip = *(unsigned long *)host->h_addr;this->cliaddr.sin_addr.s_addr = hostip;unsigned char net = hostip & 0xff;if (net > 223 && net < 240)  // 如果是多播{   char numeric_ip[32] = "\0";get_ifaddr (numeric_ip);struct in_addr outputif;outputif.s_addr = inet_addr (numeric_ip);LOG_INFO("interface = %s, numeric_ip = %s", interface, numeric_ip);if (setsockopt(this->fd, IPPROTO_IP, IP_MULTICAST_IF, (char* ) &outputif, sizeof(struct in_addr))){throw EndException(errno, strerror(errno));}}return true;
}int UDPOperation::get_ifaddr(char* addr)
{int sock = socket (AF_INET, SOCK_DGRAM, 0);struct ifreq ifr;memset (&ifr, 0, sizeof (ifr));strcpy (ifr.ifr_name, interface);if (ioctl (sock, SIOCGIFADDR, &ifr) < 0) {close (sock);throw EndException(errno, strerror(errno));return 1;}strcpy (addr, inet_ntoa(((struct sockaddr_in* ) &(ifr.ifr_addr))->sin_addr));close (sock);return 0;
}void UDPOperation::destory_udpsocket()
{close(this->fd);
}bool UDPOperation::send_buffer(char *buffer)
{socklen_t len = sizeof(struct sockaddr_in);// 数据广播int t = sendto(this->fd, buffer, SEND_UDP_PER_TSPACKET_SIZE, 0, (struct sockaddr *)&cliaddr, len);if (t == -1){LOG_ERROR("Socket send failed: %s", strerror(errno));throw BaseException(errno, strerror(errno));}return true;
}

二、接收端代码

#include <iostream>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/ioctl.h>
#include "UDPOperation.h"
#include "GlobalVariable.h"
#include "Logger.h"
#include "EndException.h"
#include "BaseException.h"UDPOperation::UDPOperation(std::string remote_host, int remote_port, char* interface) : fd(-1)
{// 创建通信的套接字this->remote_host = remote_host;this->remote_port = remote_port;this->interface = interface;memset(&(this->cliaddr), 0, sizeof(sockaddr_in));this->cliaddr.sin_family = AF_INET;this->cliaddr.sin_addr.s_addr = inet_addr(this->remote_host.c_str());this->cliaddr.sin_port = htons(this->remote_port); // 接收端需要绑定remote_port端口
}UDPOperation::~UDPOperation() {}bool UDPOperation::create_udpsocket()
{this->fd = socket(AF_INET, SOCK_DGRAM, 0);if (this->fd == -1){LOG_ERROR("Socket creation failed: %s", strerror(errno));throw EndException(errno, strerror(errno));}// 设置socket选项,允许重用地址  int reuse = 1;  if (setsockopt(this->fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0) {  LOG_ERROR("Error setting socket option: %s", strerror(errno));throw EndException(errno, strerror(errno)); }  struct sockaddr_in local_addr;      //local addressmemset(&local_addr, 0, sizeof(local_addr));local_addr.sin_family = AF_INET;local_addr.sin_addr.s_addr = inet_addr("0.0.0.0");   // 设定本地监听必须是0.0.0.0 这里是关键!local_addr.sin_port = htons(remote_port);             //this port must be the group port//建立本地捆绑(主机地址/端口号)if (bind(fd, (struct sockaddr*)&local_addr, sizeof(local_addr)) != 0){LOG_ERROR("Error binding socket: %s", strerror(errno));throw EndException(errno, strerror(errno)); }// 如果是组播 加入组播int net = stoi(remote_host.substr(0, remote_host.find('.')));if (net >= 224 && net <= 239){struct ip_mreq mreq;mreq.imr_multiaddr.s_addr = inet_addr(this->remote_host.c_str());if(strlen(interface) == 0){mreq.imr_interface.s_addr = htonl(INADDR_ANY);                //任意接口接收组播信息}else{char numeric_ip[32] = "\0";get_ifaddr (numeric_ip);LOG_INFO("interface = %s, numeric_ip = %s", interface, numeric_ip);mreq.imr_interface.s_addr = inet_addr(numeric_ip);    //指定新接口接收组播信息}if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) != 0) {LOG_ERROR("Error setting socket option for multicast: %s", strerror(errno));throw EndException(errno, strerror(errno));}}return true;
}void UDPOperation::destory_udpsocket()
{close(this->fd);
}int UDPOperation::recv_buffer(uint8_t *buffer, int size)
{socklen_t len = sizeof(struct sockaddr_in);int bytes_received = recvfrom(this->fd, buffer, size, 0, (struct sockaddr *)&this->cliaddr, &len);  if (bytes_received < 0) {  LOG_ERROR("Error receiving data: %s", strerror(errno));throw BaseException(errno, strerror(errno)); }  return bytes_received;
}int UDPOperation::get_ifaddr(char* addr)
{int sock = socket (AF_INET, SOCK_DGRAM, 0);struct ifreq ifr;memset (&ifr, 0, sizeof (ifr));strcpy (ifr.ifr_name, interface);if (ioctl (sock, SIOCGIFADDR, &ifr) < 0) {close (sock);throw EndException(errno, strerror(errno));return 1;}strcpy (addr, inet_ntoa(((struct sockaddr_in* ) &(ifr.ifr_addr))->sin_addr));close (sock);return 0;
}

三、若udp组播接收不到数据可能是如下原因

# 2. 看系统有没有过滤组播包:
# 2.1 看接受组播的网卡是否过滤了:
cat /proc/sys/net/ipv4/conf/en4/rp_filter
# 如果是0, good。
# 2.2 看all网卡是否过滤了:
cat /proc/sys/net/ipv4/conf/all/rp_filter
# 如果是0, good。
# 这两个值都必须是0,才行!如果不是0,这样修改:
# 2.3 临时修改取消过滤:
sudo sysctl -w net.ipv4.conf.en4.rp_filter=0
sudo sysctl -w net.ipv4.conf.all.rp_filter=0
# 2.4 永久修改取消过滤(重启亦有效):
sudo vi /etc/sysctl.conf
# 改为:
net.ipv4.conf.default.rp_filter=0
net.ipv4.conf.all.rp_filter=0

rp_filter参数详细介绍:
rp_filter参数有三个值,0、1、2,具体含义:

0:不开启源地址校验。

1:开启严格的反向路径校验。对每个进来的数据包,校验其反向路径是否是最佳路径。如果反向路径不是最佳路径, 则直接丢弃该数据包。

2:开启松散的反向路径校验。对每个进来的数据包,校验其源地址是否可达,即反向路径是否能通(通过任意网口),如果反向路径不同,则直接丢弃该数据包。

相关文章:

C/C++ 实现UDP发送或接收组播消息,并可指定接收发送网卡

一、发送端代码 #include <iostream> #include <unistd.h> #include <stdio.h> #include <string.h> #include <net/if.h> #include <netinet/in.h> #include <netdb.h> #include <sys/ioctl.h> #include "UDPOperation…...

纬创出售印度子公司给塔塔集团,结束iPhone代工业务 | 百能云芯

纬创&#xff08;Wistron&#xff09;董事会于10月27日通过决议&#xff0c;同意以1.25亿美元的价格出售其印度子公司Wistron InfoComm Manufacturing (India) Private Limited&#xff08;WMMI&#xff09;的100%股权给塔塔集团&#xff0c;交割将尽快完成。此举将意味着纬创退…...

vue手机项目如何控制手电筒打开与关闭

要控制手电筒&#xff0c;您可以使用Vue的Device API&#xff0c;例如cordova-plugin-flashlight或vue-native-flashlight插件。以下是一些基本步骤&#xff1a; 导入手电筒插件或库。在Vue组件中创建一个手电筒对象并初始化它。使用turnOn()和turnOff()方法控制手电筒。 以下…...

电商课堂|5分钟了解电商数据分析完整流程,建议收藏!

账户效果下降&#xff0c;如何能够快速找到问题并优化调整&#xff1f; 相信百分之90%的竞价员都会说&#xff1a;“做数据分析。” 没错&#xff0c;数据分析能够帮助我们快速锁定问题所在&#xff0c;确定优化方向&#xff0c;还可以帮助我们找到流量控制的方向。那么做电商&…...

Redis测试新手入门教程

在测试过程中&#xff0c;我们或多或少会接触到Redis&#xff0c;今天就把在小破站看到的三丰老师课程&#xff0c;把笔记整理了下&#xff0c;用来备忘&#xff0c;也希望能给大家带来亿点点收获。 主要分为两个部分&#xff1a; 一、缓存技术在后端架构中是如何应用的&#…...

Linux内核是如何创建进程?

目录 1.Linux如何创建进程 2.fork函数原理 2.1 fork函数原型 2.2 fork函数实现原理 2.3 父子进程虚拟地址空间&#xff08;mm_struct&#xff09;之间的关系 2.4 写时拷贝&#xff08;copy-on-write&#xff09;技术 2.5 父子进程如何共享文件&#xff08;files_struct&…...

IDEA 使用技巧

文章目录 语言支持简化编写 有问题&#xff0c;可暂时跳过 个人常用快捷键插件主题插件功能插件 碰到过的问题 除了一些在Linux上用vim开发的大佬&#xff0c;idea算是很友好的集成开发工具了&#xff0c;功能全面&#xff0c;使用也很广泛。 记录一下我的 IDEA 使用技巧&#…...

安防监控项目---web网页通过A9控制Zigbee终端节点的风扇

文章目录 前言一、zigbee的CGI接口二、请求线程和硬件控制三、现象展示总结 前言 书接上期&#xff0c;我们可以看一下前面的功能设计的部分&#xff0c;网页端的控制还有一个&#xff0c;那就是通过网页来控制zigbee上的风扇节点&#xff0c;这部分的工作量是相当大的&#x…...

Ubuntu 22.04 在登录界面循环

问题描述 https://blog.csdn.net/weixin_44023406/article/details/134092271?spm1001.2014.3001.5502 接上一篇&#xff0c;磁盘满了&#xff0c;扩展空间之后能正常开机&#xff0c;进到登录界面&#xff0c;输密码3秒后又回到登录界面 分析解决问题 命令行能登录&#…...

【C++ 系列文章 -- 程序员考试 201805 下午场 C++ 专题 】

文章目录 1.1 C 题目六1.1.1 填空&#xff08;1&#xff09;详解1.1.1.1 C 纯虚函数介绍 1.1.2 填空&#xff08;2&#xff09;详解1.1.2.1 父类声明了带参构造函数1.1.2.2 子类中构造函数的构造原则 1.1.3 填空&#xff08;3&#xff09;详解1.1.4 填空&#xff08;4&#xff…...

Python如何使用datetime模块进行日期和时间的操作

目录 一、引言 二、datetime模块的基本使用 三、日期的运算 四、注意事项 总结 本文将对Python的datetime模块进行深入探讨&#xff0c;阐述如何使用该模块进行日期和时间的各种操作。我们将介绍日期和时间的基本操作&#xff0c;以及格式化、时区处理等高级操作&#xff…...

flutter之bloc使用详解

flutter中一切皆为Widget&#xff0c;因此在我们开发中&#xff0c;往往业务和UI逻辑写在一起&#xff0c;这样不利于代码维护&#xff0c;因此状态管理框架久诞生了&#xff0c;这篇就开始讲一讲Bloc。 对于Bloc库有两个&#xff0c;如下图&#xff1a; flutter_bloc其实是对…...

记一次 .NET 某工厂无人车调度系统 线程爆高分析

一&#xff1a;背景 1. 讲故事 前些天有位朋友找到我&#xff0c;说他程序中的线程数爆高&#xff0c;让我帮忙看下怎么回事&#xff0c;这种线程数爆高的情况找问题相对比较容易&#xff0c;就让朋友丢一个dump给我&#xff0c;看看便知。 二&#xff1a;为什么会爆高 1. …...

高等数学啃书汇总重难点(九)多元函数微分法及其应用

下册最重要也是个人认为偏恶心的一节&#xff08;主要东西是真不少....&#xff09;重点在于会计算偏导、能理解全微分及隐函数求导3个核心内容&#xff0c;至于后面的关于几何层面的应用&#xff0c;建议掌握计算方法即可&#xff0c;学有余力再死磕推导过程等内容~ 1.平面点集…...

Vue3前端100个必要的知识点

为什么是必要的&#xff0c;就是这100个知识点学完后&#xff0c;能独立完成一个小项目。最终能得到一个解决方案。也算是前端知识的积累。如果后面有需要的地方可以回来查。100个其实比较多&#xff0c;我会按新手老鸟&#xff0c;大神来分成3个等级&#xff0c;话不多说&…...

CCS3列表和超链接样式

在默认状态下&#xff0c;超链接文本显示为蓝色、下画线效果&#xff0c;当鼠标指针移过超链接时显示为手形&#xff0c;访问过的超链接文本显示为紫色&#xff1b;而列表项目默认会缩进显示&#xff0c;并在左侧显示项目符号。在网页设计中&#xff0c;一般可以根据需要重新定…...

vue手机项目如何控制蓝牙连接

要控制蓝牙连接&#xff0c;您需要使用Vue的蓝牙插件或库&#xff0c;例如BLE-Peripheral或cordova-plugin-ble-central。以下是一些基本步骤&#xff1a; 导入蓝牙插件或库。在Vue组件中创建一个蓝牙对象并初始化它。扫描周围的蓝牙设备并连接到所需的设备。一旦连接成功&…...

遥遥领先,免费开源的django4-vue3项目

星域后台管理系统前端介绍 &#x1f33f;项目简介 本项目前端基于当下流行且常用的vue3作为主要技术栈进行开发&#xff0c;融合了typescript和element-plus-ui&#xff0c;提供暗黑模式和白昼模式两种主题以及全屏切换&#xff0c;开发bug少&#xff0c;简单易学&#xff0c…...

视频平台跨网级联视频压缩解决方案

一、 简介 视频监控领域对带宽有着较大的需求&#xff0c;这是因为视频流需要实时占用网络带宽资源。视频监控的传输带宽是组网结构的基础保障&#xff0c;关系到视频监控的稳定性、可靠性和可拓展性等因素。例如&#xff0c;720P的视频格式每路摄像头的比特率为2Mbps&#xff…...

利用python进行数据分析 pdf

利用python进行数据分析 pdf 介绍 在现代社会中&#xff0c;随着大数据时代的到来&#xff0c;数据分析的需求越来越大。而Python作为一门简洁且易于学习的编程语言&#xff0c;具有强大的数据分析能力&#xff0c;成为了广大数据分析师的首选工具之一。本文将指导一位刚入行的…...

在软件开发中正确使用MySQL日期时间类型的深度解析

在日常软件开发场景中&#xff0c;时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志&#xff0c;到供应链系统的物流节点时间戳&#xff0c;时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库&#xff0c;其日期时间类型的…...

Cursor实现用excel数据填充word模版的方法

cursor主页&#xff1a;https://www.cursor.com/ 任务目标&#xff1a;把excel格式的数据里的单元格&#xff0c;按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例&#xff0c;…...

React第五十七节 Router中RouterProvider使用详解及注意事项

前言 在 React Router v6.4 中&#xff0c;RouterProvider 是一个核心组件&#xff0c;用于提供基于数据路由&#xff08;data routers&#xff09;的新型路由方案。 它替代了传统的 <BrowserRouter>&#xff0c;支持更强大的数据加载和操作功能&#xff08;如 loader 和…...

条件运算符

C中的三目运算符&#xff08;也称条件运算符&#xff0c;英文&#xff1a;ternary operator&#xff09;是一种简洁的条件选择语句&#xff0c;语法如下&#xff1a; 条件表达式 ? 表达式1 : 表达式2• 如果“条件表达式”为true&#xff0c;则整个表达式的结果为“表达式1”…...

Springboot社区养老保险系统小程序

一、前言 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;社区养老保险系统小程序被用户普遍使用&#xff0c;为方…...

Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习)

Aspose.PDF 限制绕过方案&#xff1a;Java 字节码技术实战分享&#xff08;仅供学习&#xff09; 一、Aspose.PDF 简介二、说明&#xff08;⚠️仅供学习与研究使用&#xff09;三、技术流程总览四、准备工作1. 下载 Jar 包2. Maven 项目依赖配置 五、字节码修改实现代码&#…...

人机融合智能 | “人智交互”跨学科新领域

本文系统地提出基于“以人为中心AI(HCAI)”理念的人-人工智能交互(人智交互)这一跨学科新领域及框架,定义人智交互领域的理念、基本理论和关键问题、方法、开发流程和参与团队等,阐述提出人智交互新领域的意义。然后,提出人智交互研究的三种新范式取向以及它们的意义。最后,总结…...

基于Springboot+Vue的办公管理系统

角色&#xff1a; 管理员、员工 技术&#xff1a; 后端: SpringBoot, Vue2, MySQL, Mybatis-Plus 前端: Vue2, Element-UI, Axios, Echarts, Vue-Router 核心功能&#xff1a; 该办公管理系统是一个综合性的企业内部管理平台&#xff0c;旨在提升企业运营效率和员工管理水…...

go 里面的指针

指针 在 Go 中&#xff0c;指针&#xff08;pointer&#xff09;是一个变量的内存地址&#xff0c;就像 C 语言那样&#xff1a; a : 10 p : &a // p 是一个指向 a 的指针 fmt.Println(*p) // 输出 10&#xff0c;通过指针解引用• &a 表示获取变量 a 的地址 p 表示…...

6个月Python学习计划 Day 16 - 面向对象编程(OOP)基础

第三周 Day 3 &#x1f3af; 今日目标 理解类&#xff08;class&#xff09;和对象&#xff08;object&#xff09;的关系学会定义类的属性、方法和构造函数&#xff08;init&#xff09;掌握对象的创建与使用初识封装、继承和多态的基本概念&#xff08;预告&#xff09; &a…...