当前位置: 首页 > 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;成为了广大数据分析师的首选工具之一。本文将指导一位刚入行的…...

Golang dig框架与GraphQL的完美结合

将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用&#xff0c;可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器&#xff0c;能够帮助开发者更好地管理复杂的依赖关系&#xff0c;而 GraphQL 则是一种用于 API 的查询语言&#xff0c;能够提…...

VTK如何让部分单位不可见

最近遇到一个需求&#xff0c;需要让一个vtkDataSet中的部分单元不可见&#xff0c;查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行&#xff0c;是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示&#xff0c;主要是最后一个参数&#xff0c;透明度…...

OpenLayers 分屏对比(地图联动)

注&#xff1a;当前使用的是 ol 5.3.0 版本&#xff0c;天地图使用的key请到天地图官网申请&#xff0c;并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能&#xff0c;和卷帘图层不一样的是&#xff0c;分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...

selenium学习实战【Python爬虫】

selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...

tree 树组件大数据卡顿问题优化

问题背景 项目中有用到树组件用来做文件目录&#xff0c;但是由于这个树组件的节点越来越多&#xff0c;导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多&#xff0c;导致的浏览器卡顿&#xff0c;这里很明显就需要用到虚拟列表的技术&…...

Xen Server服务器释放磁盘空间

disk.sh #!/bin/bashcd /run/sr-mount/e54f0646-ae11-0457-b64f-eba4673b824c # 全部虚拟机物理磁盘文件存储 a$(ls -l | awk {print $NF} | cut -d. -f1) # 使用中的虚拟机物理磁盘文件 b$(xe vm-disk-list --multiple | grep uuid | awk {print $NF})printf "%s\n"…...

中医有效性探讨

文章目录 西医是如何发展到以生物化学为药理基础的现代医学&#xff1f;传统医学奠基期&#xff08;远古 - 17 世纪&#xff09;近代医学转型期&#xff08;17 世纪 - 19 世纪末&#xff09;​现代医学成熟期&#xff08;20世纪至今&#xff09; 中医的源远流长和一脉相承远古至…...

return this;返回的是谁

一个审批系统的示例来演示责任链模式的实现。假设公司需要处理不同金额的采购申请&#xff0c;不同级别的经理有不同的审批权限&#xff1a; // 抽象处理者&#xff1a;审批者 abstract class Approver {protected Approver successor; // 下一个处理者// 设置下一个处理者pub…...

鸿蒙(HarmonyOS5)实现跳一跳小游戏

下面我将介绍如何使用鸿蒙的ArkUI框架&#xff0c;实现一个简单的跳一跳小游戏。 1. 项目结构 src/main/ets/ ├── MainAbility │ ├── pages │ │ ├── Index.ets // 主页面 │ │ └── GamePage.ets // 游戏页面 │ └── model │ …...

【安全篇】金刚不坏之身:整合 Spring Security + JWT 实现无状态认证与授权

摘要 本文是《Spring Boot 实战派》系列的第四篇。我们将直面所有 Web 应用都无法回避的核心问题&#xff1a;安全。文章将详细阐述认证&#xff08;Authentication) 与授权&#xff08;Authorization的核心概念&#xff0c;对比传统 Session-Cookie 与现代 JWT&#xff08;JS…...