UDP特性之组播(多播)

UDP特性之组播

  • 1. 组播的特点
  • 2. 设置主播属性
    • 2.1 发送端
    • 2.2 接收端
  • 3. 组播通信流程
    • 3.1 发送端
    • 3.2 接收端
  • 4. 通信代码

原文链接

在公司测试广播和多播有一点问题。。。

1. 组播的特点

组播也可以称之为多播这也是UDP的特性之一。组播是主机间一对多的通讯模式,是一种允许一个或多个组播源发送同一报文到多个接收者的技术。组播源将一份报文发送到特定的组播地址,组播地址不同于单播地址,它并不属于特定某个主机,而是属于一组主机。一个组播地址表示一个群组,需要接收组播报文的接收者都加入这个群组。

  • 广播只能在局域网访问内使用,组播既可以在局域网中使用,也可以用于广域网
  • 在发送广播消息的时候,连接到局域网的客户端不管想不想都会接收到广播数据,组播可以控制发送端的消息能够被哪些接收端接收,更灵活和人性化。
  • 广播使用的是广播地址,组播需要使用组播地址。
  • 广播和组播属性默认都是关闭的,如果使用需要通过setsockopt()函数进行设置。

组播需要使用组播地址,在 IPv4 中它的范围从 224.0.0.0 239.255.255.255,并被划分为局部链接多播地址、预留多播地址和管理权限多播地址三类:
在这里插入图片描述
组播地址不属于任何服务器或个人,它有点类似一个微信群号,任何成员(组播源)往微信群(组播IP)发送消息(组播数据),这个群里的成员(组播接收者)都会接收到此消息。

2. 设置主播属性

如果使用组播进行数据的传输,不管是消息发送端还是接收端,都需要进行相关的属性设置,设置函数使用的是同一个,即:setsockopt()。

2.1 发送端

发送组播消息的一端需要设置组播属性,具体的设置方式如下:

int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);
  • 参数:

    • sockfd:用于UDP通信的套接字

    • level:套接字级别,设置组播属性需要将该参数指定为:IPPTOTO_IP

    • optname: 套接字选项名,设置组播属性需要将该参数指定为:IP_MULTICAST_IF

    • optval:设置组播属性,这个指针需要指向一个struct in_addr{} 类型的结构体地址,这个结构体地址用于存储组播地址,并且组播IP地址的存储方式是大端的。

    • optlen:optval指针指向的内存大小,即:sizeof(struct in_addr)

struct in_addr
{in_addr_t s_addr;	// unsigned int
}; 
  • 返回值:函数调用成功返回0,调用失败返回-1

2.2 接收端

因为一个组播地址表示一个群组,所以需要接收组播报文的接收者都加入这个群组,和想要接收群消息就必须要先入群是一个道理。加入到这个组播群组的方式如下:

int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);
  • 参数:

    • sockfd:基于udp的通信的套接字

    • level:套接字级别,加入到多播组该参数需要指定为:IPPTOTO_IP

    • optname:套接字选项名,加入到多播组该参数需要指定为:IP_ADD_MEMBERSHIP

    • optval:加入到多播组,这个指针应该指向一个struct ip_mreqn{}类型的结构体地址

    • optlen:optval指向的内存大小,即:sizeof(struct ip_mreqn)

typedef unsigned int  uint32_t;
typedef uint32_t in_addr_t;
struct sockaddr_in addr;struct in_addr
{in_addr_t s_addr;	// unsigned int
};struct ip_mreqn
{struct in_addr imr_multiaddr;   // 组播地址/多播地址struct in_addr imr_address;     // 本地地址int   imr_ifindex;              // 网卡的编号, 每个网卡都有一个编号
};
// 必须通过网卡名字才能得到网卡的编号: 可以通过 ifconfig 命令查看网卡名字
#include <net/if.h>
// 将网卡名转换为网卡的编号, 参数是网卡的名字, 比如: "ens33"
// 返回值就是网卡的编号
unsigned int if_nametoindex(const char *ifname);

3. 组播通信流程

发送组播消息的一端需要将数据发送到组播地址和固定的端口上,想要接收组播消息的终端需要绑定对应的固定端口然后加入到组播的群组,最终就可以实现数据的共享。

在这里插入图片描述

3.1 发送端

  1. 创建通信的套接字
// 第二个参数是 SOCK_DGRAM, 第三个参数0表示使用报式协议中的udp
int fd = socket(AF_INET, SOCK_DGRAM, 0);
  1. 主动发送数据的一端不需要手动绑定端口(自动随机分配就可以了),设置UDP组播属性
// 设置组播属性
struct in_addr opt;
// 将组播地址初始化到这个结构体成员中
inet_pton(AF_INET, "239.0.1.10", &opt.s_addr);
setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, &opt, sizeof(opt));
  1. 使用组播地址发送组播消息到固定的端口(接收端需要绑定这个端口)
sendto();
  1. 关闭套接字(文件描述符)
close(fd);

3.2 接收端

  1. 创建通信的套接字
// 第二个参数是 SOCK_DGRAM, 第三个参数0表示使用报式协议中的udp
int fd = socket(AF_INET, SOCK_DGRAM, 0);
  1. 绑定固定的端口,发送端应该将数据发送到接收端绑定的端口上
bind();
  1. 加入到组播的群组中,入群之后就可以接受组播消息了。
// 加入到多播组
struct ip_mreqn opt;
// 要加入到哪个多播组, 通过组播地址来区分
inet_pton(AF_INET, "239.0.1.10", &opt.imr_multiaddr.s_addr);
opt.imr_address.s_addr = INADDR_ANY;
opt.imr_ifindex = if_nametoindex("ens33");
setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &opt, sizeof(opt));
  1. 接收组播数据
recvfrom();
  1. 关闭套接字(文件描述符)
close(fd);

4. 通信代码

发送端

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>int main()
{// 1. 创建通信的套接字int fd = socket(AF_INET, SOCK_DGRAM, 0);if(fd == -1){perror("socket");exit(0);}// 2. 设置组播属性struct in_addr opt;// 将组播地址初始化到这个结构体成员中即可inet_pton(AF_INET, "239.0.1.10", &opt.s_addr);setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, &opt, sizeof(opt));char buf[1024];struct sockaddr_in cliaddr;int len = sizeof(cliaddr);cliaddr.sin_family = AF_INET;cliaddr.sin_port = htons(9999); // 接收端需要绑定9999端口// 发送组播消息, 需要使用组播地址, 和设置组播属性使用的组播地址一致就可以inet_pton(AF_INET, "239.0.1.10", &cliaddr.sin_addr.s_addr);// 3. 通信int num = 0;while(1){sprintf(buf, "hello, client...%d\n", num++);// 数据广播sendto(fd, buf, strlen(buf)+1, 0, (struct sockaddr*)&cliaddr, len);printf("发送的组播的数据: %s\n", buf);sleep(1);}close(fd);return 0;
}

注意事项:在组播数据的发送端,需要先设置组播属性,发送的数据是通过sendto()函数发送到某一个组播地址上,并且在程序中数据发送到了接收端的9999端口,因此接收端程序必须要绑定这个端口才能收到组播消息。

接收端

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <net/if.h>int main()
{// 1. 创建通信的套接字int fd = socket(AF_INET, SOCK_DGRAM, 0);if(fd == -1){perror("socket");exit(0);}// 2. 通信的套接字和本地的IP与端口绑定struct sockaddr_in addr;addr.sin_family = AF_INET;addr.sin_port = htons(9999);    // 大端addr.sin_addr.s_addr = INADDR_ANY;  // 0.0.0.0int ret = bind(fd, (struct sockaddr*)&addr, sizeof(addr));if(ret == -1){perror("bind");exit(0);}// 3. 加入到多播组struct ip_mreqn opt;// 要加入到哪个多播组, 通过组播地址来区分inet_pton(AF_INET, "239.0.1.10", &opt.imr_multiaddr.s_addr);opt.imr_address.s_addr = INADDR_ANY;opt.imr_ifindex = if_nametoindex("ens33");  //  enp0s3setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &opt, sizeof(opt));char buf[1024];// 3. 通信while(1){// 接收广播消息memset(buf, 0, sizeof(buf));// 阻塞等待数据达到recvfrom(fd, buf, sizeof(buf), 0, NULL, NULL);printf("接收到的组播消息: %s\n", buf);}close(fd);return 0;
}

注意事项:作为组播消息的接收端,必须要先绑定一个固定端口(发送端就可以把数据发送到这个固定的端口上了),然后加入到组播的群组中(一个组播地址可以看做是一个群组),这样就可以接收到组播消息了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/230701.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

URP管线下Shader中的SubShader Tags、Pass Tags、ShaderLab Commands总结

一、SubShader Tags SubShader Tags是提供SubShader信息的键值对&#xff0c;它们允许你指定特定的设置好让渲染管线知道如何处理SubShader。 下面分别介绍一下SubShader中的tag。 1、 RenderPipeline 这个tag用来指定SubShader的目标渲染管线&#xff0c;不同的渲染管线有特定…

Vue3源码梳理:运行时之基于h函数生成vnode的内部流程

VNode 节点类型 对于vnode而言&#xff0c;具备很多节点类型vue源码中patch函数switch处理包含了好几种类型&#xff0c;常见类型如下 Text&#xff1a;文本节点Comment&#xff1a;注释节点Static&#xff1a;静态dom节点Fragment&#xff1a;包含多个根节点的模板被表示为一…

SHT10温湿度传感器——STM32驱动

———————实验效果——————— &#x1f384;硬件外观 &#x1f384;接线 &#x1f388; 3.3V供电 &#x1f388; IIC通讯 &#x1f384; 代码获取 &#x1f388; 查看下方 ———————END———————

FB使用汇编模拟GoSub(子函数)功能

在FB里不支持GoSub功能&#xff0c;在面对函数内简单又重复的操作&#xff0c;而所涉及变量又比较多的时候&#xff0c;再在外边定义一个函数就显得累赘&#xff0c;此时如果可以有一个函数内部的子函数&#xff0c;就显得方便多了。 在汇编探索里发现&#xff0c;可以使用汇编…

20231218在微软官网下载WINDOWS10以及通过rufus-4.3p写入U盘作为安装盘

20231218在微软官网下载WINDOWS10以及通过rufus-4.3p写入U盘作为安装盘 2023/12/18 17:06 百度搜索&#xff1a;下载 windows10 https://www.microsoft.com/zh-cn/software-download/windows10 下载 Windows 10 更新之前&#xff0c;请参阅 Windows 版本信息状态中的已知问题&a…

企业要想成功就必须培养“支持说真话的文化”

大家好&#xff0c;欢迎来到我的博客。今天&#xff0c;我想和大家谈谈企业文化的重要性&#xff0c;特别是支持说真话的文化。 1. 为什么说真话很重要&#xff1f; 在当今社会&#xff0c;说真话似乎越来越难了。我们害怕得罪别人&#xff0c;害怕被孤立&#xff0c;害怕被认…

系统设计——系统安全

HTTPS 是如何工作的&#xff1f; 安全超文本传输​​协议&#xff08;HTTPS&#xff09;是超文本传输​​协议&#xff08;HTTP&#xff09;的扩展。HTTPS 使用传输层安全性&#xff08;TLS&#xff09;传输加密数据。如果数据在网上被劫持&#xff0c;劫持者得到的只是二进制…

php去掉数组的key,重组数组的方法

php去掉数组的key&#xff0c;重组数组的方法 方法一&#xff1a;foreach循环方法二&#xff1a;array_values()函数方法三&#xff1a;array_map()函数方法四&#xff1a;强制类型转换 方法一&#xff1a;foreach循环 使用foreach循环遍历数组时&#xff0c;可以只取出数组的…

TaxtArea中内嵌一张放松图片,该图片实现属性悬浮放大功能

TaxtArea中内嵌一张发送图片&#xff0c;该图片实现属性悬浮放大功能&#xff0c;离开还原效果&#xff0c;点击发送按钮后&#xff0c;发送图片变为loading&#xff0c; <div class"textarea-wrapper" ><a-textarearef"textArea"v-model.trim&q…

汇编语言学习(3)

更好的阅读体验&#xff0c;请点击 YinKai s Blog 。 内存段 ​ 上面讨论的汇编程序的三个部分&#xff0c;也代码各种内存段。 ​ 有趣的是&#xff0c;如果将 section 关键字替换为 segment&#xff0c;将会得到相同的结果&#xff0c;这是因为对于汇编器而言&#xff0c;这…

web应用开发技术的一些概念

一、Servlet 1.Servlet的工作过程&#xff1a; Servelt的工作流程示意图 &#xff08;1&#xff09;客户端发起一个Http请求到服务器&#xff0c;请求特定的资源或者是要执行特定的操作 &#xff08;2&#xff09;服务器在接收到请求后&#xff0c;根据请求相应的URL将请求分发…

PostgreSQL进阶操作

PostgreSQL进阶操作 SQL执行顺序 (9) SELECT (10) DISTINCT col1, [OVER()] (6) AGG_FUNC(col2) (1) FROM table1 (3) JOIN table2 (2) ON table1.col table2.col (4) WHERE constraint_expression (5) GROUP BY col (7) WITH CUBE|ROLLUP (8) HAVING constraint_expression…

21、同济、微软亚研院、西安电子科技大提出HPT:层次化提示调优,独属于提示学习的[安妮海瑟薇]

前言&#xff1a; 本论文由同济大学、微软亚洲研究院、西安电子科技大学&#xff0c;于2023年12月11日中了AAAI2024 论文&#xff1a; 《Learning Hierarchical Prompt with Structured Linguistic Knowledge for Vision-Language Models》 地址&#xff1a; [2312.06323]…

C++泛型超详细合集-泛化的编程方式-程序员编写一个函数/类的代码让编译器去填补出不同的函数实现-供大家学习研究参考

以Add函数为例&#xff0c;在函数模板存在的同时&#xff0c;我们还可以单独写一个int类型的add函数。这都归功于函数重载的存在。 同时&#xff0c;我们还可以使用<int>来指定函数模板重载为已存在的Add函数。因为本质上这两个函数是不同的&#xff0c;并不会冲突。 下…

js 数据类型

js的八种数据类型&#xff1a; 基本类型&#xff08;基本类型&#xff09;&#xff1a;Number&#xff0c;String&#xff0c;Boolean&#xff0c;Undefined&#xff0c;Null&#xff0c;Symbol 引用数据类型&#xff08;对象类型&#xff09;&#xff1a;Object&#xff0c;…

mybatis中xml文件容易搞混的属性

目录 第一章、1.1&#xff09;MyBatis中resultMap标签1.2&#xff09;MyBatis的resultType1.3&#xff09;MyBatis的parameterType1.4&#xff09;type属性1.5&#xff09;jdbcType属性1.6&#xff09;javaType属性1.7&#xff09;ofType属性 友情提醒: 先看文章目录&#xff…

【k8s】--insecure-registry详解 ( 访问仓库、https、http)

文章目录 一、--insecure-registry是什么二、如何使用--insecure-registry三、--insecure-registry的安全风险四、--insecure-registry的替代方案五、总结参考 一、–insecure-registry是什么 --insecure-registry是docker中用来设置与docker registry通信的安全限制的一个参数…

猫粮哪个牌子好又安全?好又安全的主食冻干猫粮牌子推荐

现在越来越多的铲屎官关注猫咪的食品选择&#xff0c;而冻干猫粮一直是热门话题。其中主食冻干的肉含量很高&#xff0c;富含猫咪成长所需的蛋白质、维生素等营养物质。而且冻干工艺还保留了食材的原始风味&#xff0c;复水后可以恢复鲜肉的口感&#xff0c;猫咪很喜欢吃&#…

人工智能Keras图像分类器(CNN卷积神经网络的图片识别篇)

上期文章我们分享了人工智能Keras图像分类器(CNN卷积神经网络的图片识别的训练模型),本期我们使用预训练模型对图片进行识别:Keras CNN卷积神经网络模型训练 导入第三方库 from keras.preprocessing.image import img_to_array from keras.models import load_model impor…

.net web API的文件传输(上传和下载)客户端winform

防止反复造轮子&#xff0c;直接上代码。 客户端代码如下&#xff1a; using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.IO; using System.IO.Compression; using System.Linq; using …