C语言网络编程实现组播(多播)

1、组播IP划分

224.0.0.0~224.0.0.255		为预留的组播地址(永久组地址),地址224.0.0.0保留不做分配,其它地址供路由协议使用;
224.0.1.0~224.0.1.255		是公用组播地址,可以用于Internet;欲使用需申请。
224.0.2.0~238.255.255.255	为用户可用的组播地址(临时组地址),全网范围内有效;
239.0.0.0~239.255.255.255	为本地管理组播地址,仅在特定的本地范围内有效。

2、多播地址与 MAC 地址的映射

IPv4 的 D 类地址是多播地址。IEEE 把一块以太网多播组地址分给 IANA 以支持IP多播。块的地址都以01:00:5e 开头,第 25 位为 0,低 23 位为 IPv4 多播地址( D类地址 )的低 23 位。
IPv4 多播地址与 MAC 地址的映射关系如图所示



由于多播地址( D类地址 )中的最高 5bit 在映射过程中被忽略,因此每个以太网多播地址对应的多播组是不唯一的。32 个不同的多播组号被映射为一个以太网地址。例如,多播地址 224.128.64.32(十六进制 e0.80.40.20)和 224.0.64.32(十六进制 e0.00.40.20)都映射为同一以太网地址01:00:5e:00:40:20。

既然地址映射是不唯一的,那么设备驱动程序或IP层就必须对数据报进行过滤。因为网卡可能接收到主机不想接收的多播数据帧,如下图,假如主机 1 加入的多播为 224.128.64.32,主机 2 加入的多播为 224.0.64.32,我们想给 224.0.64.32 所在的多播组 ( 主机 2 ) 发送信息,数据经过网卡时,224.128.64.32 (主机 1 ) 和 224.0.64.32 (主机 2 ) 所在多播组的网卡都会收到数据,因为它们的 MAC 地址都是 01:00:5e:00:40:20。这时候,如果网卡不提供足够的多播数据帧过滤功能,设备驱动程序就必须接收所有多播数据帧,然后对它们进行过滤,这个过滤过程是网络驱动或IP层自动完成。

4、套接字选项

#include <sys/types.h>
#include <sys/socket.h>int setsockopt(int sockfd, int level, int optname,const void *optval, socklen_t optlen);
int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t*optlen);

sockfd:标识一个套接口的描述字。
level:选项定义的层次;支持
SOL_SOCKET
IPPROTO_TCP
IPPROTO_IP
IPPROTO_IPV6

optname:需设置的选项。
optval:指针,指向存放选项待设置的新值的缓冲区。
optlen:optval缓冲区长度。 

a、选项 IP_MULTICASE_TTL

允许设置超时TTL,范围为0~255之间的任何值,例如:

unsigned char ttl=255; 
setsockopt(s,IPPROTO_IP,IP_MULTICAST_TTL,&ttl,sizeof(ttl));

 b、选项IP_MULTICAST_IF

用于设置组播的默认网络接口,会从给定的网络接口发送,另一个网络接口会忽略此数据。例如:

struct in_addr
{in_addr_t s_addr;
}
struct in_addr addr; 
setsockopt(s,IPPROTO_IP,IP_MULTICAST_IF,&addr,sizeof(addr))

c 、选项IP_MULTICAST_LOOP

用于控制数据是否回送到本地的回环接口。例如:

unsigned char loop; 
setsockopt(s,IPPROTO_IP,IP_MULTICAST_LOOP,&loop,sizeof(loop))

参数loop设置为0禁止回送,设置为1允许回送

d、选项IP_ADD_MEMBERSHIP

加入某个广播组,之后就可以向这个广播组发送数据或者从广播组接收数据。此选项的值为mreq结构,成员imn_multiaddr是需要加入的广播组IP地址,成员imr_interface是本机需要加入广播组的网络接口IP地址。例如:

struct ip_mreq 
{ struct in_addr imn_multiaddr; /*加入或者退出的广播组IP地址*/ struct in_addr imr_interface; /*加入或者退出的网络接口IP地址*/ 
}struct ip_mreq mreq; 
setsockopt(s,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq))

 e、选项IP_DROP_MEMBERSHIP

用于从一个广播组中退出。例如:

struct ip_mreq mreq; 
setsockopt(s,IPPROTP_IP,IP_DROP_MEMBERSHIP,&mreq,sizeof(sreq))

其中mreq包含了在IP_ADD_MEMBERSHIP中相同的值.
 

f、选项SO_REUSEADDR

是一个 socket 选项,用于在关闭 TCP 连接后立即再次使用相同的地址和端口。如果不使用该选项,那么一般情况下要等待一段时间(TIME_WAIT)才能再次使用相同的地址和端口。

int opt = 1;
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const void  *)&opt, sizeof(opt));

g、选项SO_BINDTODEVICE

指定网卡去发送数据
 

struct ifreq
{char ifr_name[IFNAMSIZ]; /* Interface name */union {struct sockaddrifr_addr;struct sockaddrifr_dstaddr;struct sockaddrifr_broadaddr;struct sockaddrifr_netmask;struct sockaddrifr_hwaddr;short ifr_flags;int ifr_ifindex;int ifr_metric;int ifr_mtu;struct ifmapifr_map;char ifr_slave[IFNAMSIZ];char ifr_newname[IFNAMSIZ];char *ifr_data;};
};struct ifreq interface;
memset(&interface,0,sizeof(interface));
strncpy(interface.ifr_ifrn.ifrn_name, “br0”, strlen(ifname));
setsockopt(fd , SOL_SOCKET, SO_BINDTODEVICE, (char *)&interface, sizeof(interface))

5、文件控制

#include <fcntl.h>int fcntl(int fd, int cmd);int curFlags = fcntl(fd, F_GETFL, 0);
fcntl(fd, F_SETFL, curFlags|O_NONBLOCK);设置非阻塞模式

6、接收示例

/* 
*broadcast_client.c - 多播的客户端 
*/ 
#define MCAST_PORT 8888; 
#define MCAST_ADDR "224.0.0.88" /*一个局部连接多播地址,路由器不进行转发*/ 
#define MCAST_INTERVAL 5 /*发送间隔时间*/ 
#define BUFF_SIZE 256 /*接收缓冲区大小*/int main(int argc, char*argv[]) 
{ int s; /*套接字文件描述符*/ struct sockaddr_in local_addr; /*本地地址*/ int err = -1; s = socket(AF_INET, SOCK_DGRAM, 0); /*建立套接字*/ if (s == -1) { perror("socket()"); return -1; } /*初始化地址*/ memset(&local_addr, 0, sizeof(local_addr)); local_addr.sin_family = AF_INET; local_addr.sin_addr.s_addr = htonl(INADDR_ANY); local_addr.sin_port = htons(MCAST_PORT); /*绑定socket*/ err = bind(s,(struct sockaddr*)&local_addr, sizeof(local_addr)) ; if(err < 0) { perror("bind()"); return -2; } /*设置回环许可*/ int loop = 1; err = setsockopt(s,IPPROTO_IP, IP_MULTICAST_LOOP,&loop, sizeof(loop)); if(err < 0) { perror("setsockopt():IP_MULTICAST_LOOP"); return -3; } struct ip_mreq mreq; /*加入广播组*/ mreq.imr_multiaddr.s_addr = inet_addr(MCAST_ADDR); /*广播地址*/ mreq.imr_interface.s_addr = htonl(INADDR_ANY); /*网络接口为默认*/ /*将本机加入广播组*/ err = setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP,&mreq, sizeof (mreq)); if (err < 0) { perror("setsockopt():IP_ADD_MEMBERSHIP"); return -4; } int times = 0; int addr_len = 0; char buff[BUFF_SIZE]; int n = 0; /*循环接收广播组的消息,5次后退出*/ for(times = 0;times<5;times++)  { addr_len = sizeof(local_addr); memset(buff, 0, BUFF_SIZE); /*清空接收缓冲区*/ /*接收数据*/ n = recvfrom(s, buff, BUFF_SIZE, 0,(struct sockaddr*)&local_addr, &addr_len); if( n== -1)  { perror("recvfrom()"); } /*打印信息*/ printf("Recv %dst message from server:%s\n", times, buff); sleep(MCAST_INTERVAL); } /*退出广播组*/ err = setsockopt(s, IPPROTO_IP, IP_DROP_MEMBERSHIP,&mreq, sizeof (mreq)); close(s); return 0; 
}

7、发送示例

/* 
*broadcast_server.c - 多播服务程序 
*/ 
#define MCAST_PORT 8888; 
#define MCAST_ADDR "224.0.0.88"/ /*一个局部连接多播地址,路由器不进行转发*/ 
#define MCAST_DATA "BROADCAST TEST DATA" /*多播发送的数据* 
#define MCAST_INTERVAL 5 /*发送间隔时间*/ 
int main(int argc, char*argv) 
{ int s; struct sockaddr_in mcast_addr; s = socket(AF_INET, SOCK_DGRAM, 0); /*建立套接字*/ if (s == -1) { perror("socket()"); return -1; } memset(&mcast_addr, 0, sizeof(mcast_addr));    /*初始化IP多播地址为0*/ mcast_addr.sin_family = AF_INET;             /*设置协议族类行为AF*/ mcast_addr.sin_addr.s_addr = inet_addr(MCAST_ADDR);/*设置多播IP地址*/ mcast_addr.sin_port = htons(MCAST_PORT);             /*设置多播端口*/ /*向多播地址发送数据*/ while(1) { int n = sendto(s,MCAST_DATA, sizeof(MCAST_DATA),0, (struct sockaddr*)&mcast_addr, sizeof(mcast_addr)) ; if( n < 0) { perror("sendto()"); return -2; } sleep(MCAST_INTERVAL); /*等待一段时间*/ } return 0;
}

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

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

相关文章

Scala的特质trait与java的interface接口的区别,以及Scala特质的自身类型和依赖注入

1. Scala的特质trait与java接口的区别 Scala中的特质&#xff08;trait&#xff09;和Java中的接口&#xff08;interface&#xff09;在概念和使用上有一些区别&#xff1a; 默认实现&#xff1a;在Java中&#xff0c;接口只能定义方法的签名&#xff0c;而没有默认实现。而在…

机器连接和边缘计算

以一种高效、可扩展的方式进行连接和边缘计算的结合&#xff0c;解决了在工业物联网应用中的机器数据集成问题。 一 边缘计算 边缘计算描述了由中央平台管理的数据分散式处理&#xff0c;它对于工业物联网而言非常重要。在许多应用程序中&#xff0c;由于数据量非常大&#xf…

【USRP】集成化仪器系列1 :信号源,基于labview实现

USRP 信号源 1、设备IP地址&#xff1a;默认为192.168.10.2&#xff0c;请勿 修改&#xff0c;运行阶段无法修改。 2、天线输出端口是TX1&#xff0c;请勿修改。 3、通道&#xff1a;0 对应RF A、1 对应 RF B&#xff0c;运行 阶段无法修改。 4、中心频率&#xff1a;当需要…

界面控件DevExpress .NET应用安全 Web API v23.1亮点:支持Swagger模式

DevExpress拥有.NET开发需要的所有平台控件&#xff0c;包含600多个UI控件、报表平台、DevExpress Dashboard eXpressApp 框架、适用于 Visual Studio的CodeRush等一系列辅助工具。 DevExpress 今年第一个重要版本v23.1日前已正式发布了&#xff0c;该版本拥有众多新产品和数十…

电子学会 2023年3月 青少年软件编程Python编程等级考试三级真题解析(选择题+判断题+编程题)

青少年编程Python编程等级考试三级真题解析(选择题+判断题+编程题) 2023年3月 一、选择题(共25题,共50分) 十进制数111转换成二进制数是?( ) A. 111 B. 1111011 C. 101111 D. 1101111 答案选:D 考点分析:考察python 进制转换 十进制转二进制,采用除二倒取余数,直到商…

使用 SQL 的方式查询消息队列数据以及踩坑指南

Pulsar-sql.png 背景 为了让业务团队可以更好的跟踪自己消息的生产和消费状态&#xff0c;需要一个类似于表格视图的消息列表&#xff0c;用户可以直观的看到发送的消息&#xff1b;同时点击详情后也能查到消息的整个轨迹。 消息列表 点击详情后查看轨迹 原理介绍 由于 Pulsar …

MyBatis关联关系映射详解

前言 在使用MyBatis进行数据库操作时&#xff0c;关联关系映射是一个非常重要的概念。它允许我们在数据库表之间建立关联&#xff0c;并通过对象之间的关系来进行数据查询和操作。本文将详细介绍MyBatis中的关联关系映射&#xff0c;包括一对一、一对多和多对多关系的处理方法…

Spring MVC:域对象共享数据

Spring MVC 前言域对象共享数据使用 ModelAndView 向 request 域对象中共享数据使用 Map 、Model 或 ModelMap 向 request 域对象中共享数据使用 SesionAttributes 注解向 session 域对象中共享数据使用 Servlet API 向 application 域对象中共享数据 附 前言 在上一章中&…

Linux搭建GitLab私有仓库,并内网穿透实现公网访问

目录 前言 1.下载Gitlab 2.安装Gitlab 3.启动Gitlab 4.安装cpolar 5. 创建隧道配置访问地址 6.固定GitLab访问地址 7. 配置二级子域名 8. 测试访问二级子域名 前言 GitLab 是一个用于仓库管理系统的开源项目&#xff0c;使用Git作为代码管理工具&#xff0c;并在此基…

问道管理:什么是大盘?大盘股又是什么?

聊到股市就免不了聊到大盘&#xff0c;有些新进场的投资者对此或许带有疑问&#xff0c;什么是大盘&#xff1f;我们所说的大盘股又是什么&#xff1f;关于这些&#xff0c;问道管理为我们准备了以下参考内容。 什么是大盘&#xff1f; 大盘&#xff0c;主要是指股市的整体行情…

python-数据分析-numpy、pandas、matplotlib的常用方法

一、numpy import numpy as np1.numpy 数组 和 list 的区别 输出方式不同 里面包含的元素类型 2.构造并访问二维数组 使用 索引/切片 访问ndarray元素 切片 左闭右开 np.array(list) 3.快捷构造高维数组 np.arange() np.random.randn() - - - 服从标准正态分布- - - …

CSS 一个好玩的卡片“开卡效果”

文章目录 一、用到的一些CSS技术二、实现效果三、代码 一、用到的一些CSS技术 渐变 conic-gradientbox-shadowclip-path变换、过渡 transform、transition动画 animation keyframes伪类、伪元素 :hover、::before、::after …绝对布局。。。 clip-path 生成网站 https://techb…

Yjs + Quill 实现文档多人协同编辑器开发(基础+实战)

前言 多人协同开发确实是比较难的知识点&#xff0c;在技术实现上有一定挑战&#xff0c;但随着各种技术库的发展&#xff0c;目前已经有了比较成熟的解决方案。今介绍 Yjs 基于CRDT算法&#xff0c;用于构建自动同步的协作应用程序&#xff0c;与Quill富文本编辑器&#xff0c…

从零开始学习 Java:简单易懂的入门指南之Collection集合及list集合(二十一)

Collection集合及list集合 1.Collection集合1.1数组和集合的区别1.2集合类体系结构1.3Collection 集合概述和使用1.4Collection集合的遍历1.4.1 迭代器遍历1.4.2 增强for1.4.3 lambda表达式 2.List集合2.1List集合的概述和特点2.2List集合的特有方法2.3List集合的五种遍历方式2…

仓库运行状况如何得知?数据挖掘是关键!

库存、订单、出入库记录、物流信息、货物状态等数据&#xff0c;是仓库管理的重要组成部分。 仓库数据的重要性 做好仓库数据管理对企业的重要性不言而喻。通过有效地管理数据&#xff0c;企业可以更好地了解市场需求和库存情况&#xff0c;快速响应市场变化&#xff0c;提高库…

医院小程序如何在线搭建?实战解析

在当今数字化时代&#xff0c;移动应用程序成为我们生活中必不可少的一部分。特别是在医疗领域&#xff0c;移动应用程序的需求更为迫切。为了满足这一需求&#xff0c;开发一个医疗小程序成为了许多医疗机构的优先选择。 在本文中&#xff0c;我们将分享一个实战攻略&#xff…

iOS开发Swift-5-自动布局AutoLayout-摇骰子App

1.在iOS坐标系中&#xff0c;以向左、向下为正方向。图片以左上角为基准点。 2.打开之前的摇骰子App&#xff0c;对它的界面做一些适应所有iPhone机型的效果。 3.先对上方logo做一个y轴约束和一个宽高约束。 宽高约束&#xff1a; 水平居中&#xff1a; 对y轴进行约束。将虚线点…

WebDAV之π-Disk派盘 + 思源笔记

思源笔记是一款隐私优先的个人知识管理系统,支持完全离线使用,同时也支持端到端加密同步。 融合块、大纲和双向链接,重构你的思维。 π-Disk派盘 – 知识管理专家 派盘是一款面向个人和企业的本地云存储解决方案,它可以帮助用户打造“数字第二大脑”,并支持KMS知识管理系…

专访远航汽车远勤山:踏踏实实做好产品 直面挑战乘风远航

8月25日&#xff0c;第二十六届成都国际汽车展览会在中国西部国际博览城隆重开幕。车展举办期间&#xff0c;远航汽车董事长远勤山先生、产品研发总监王震先生向媒体分享了远航汽车品牌发展、产品研发、技术创新以及市场布局等内容。 “通过我们的付出和努力&#xff0c;让我们…

全网最新最全软件测试工程师面试题,看完金九银十还怕拿不到offer?

与开发工程师相比&#xff0c;软件测试工程师前期可能不会太深&#xff0c;但涉及面还是很广的。 在一年左右的实习生或岗位的早期面试中&#xff0c;主要是问一些基本的问题。 涉及到的知识主要包括MySQL数据库的使用、Linux操作系统的使用、软件测试框架问题、测试环境搭建问…