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

广播与组播

文章目录

  • 广播
    • 核心概念
    • 广播地址
    • 实现流程
      • 发送端
      • 接收端
    • demo
  • 组播(多播)
    • 核心概念
    • 组播地址
    • 核心结构体
      • ip_mreq(常用)
      • ip_mreqn(含网卡编号,更精细)
    • 实现流程
      • 接收端
      • 发送端
    • demo
  • 广播 VS 组播
  • 广播和组播均为UDP 协议专属的数据包发送方式(TCP 为面向连接的单播,不支持),用于实现一对多的网络数据传输,二者在传输范围、寻址方式、实现方式上存在核心差异

广播

核心概念

  • 广播是局域网内的一对所有传输:将数据包发送到局域网中所有主机,所有主机均可接收该数据包
  • 仅 UDP(用户数据报套接字)支持广播,TCP 因面向连接的特性无法实现
  • 单播为 “一对一” 传输,是与广播对应的基础传输方式

广播地址

  • 核心规则:一个网络内主机号全为 1 的 IP 地址为该网段的广播地址,发往此地址的数据包会被网段内所有主机接收;
  • 通用广播地址:255.255.255.255,在所有网段中均表示广播地址,适用于本地局域网广播

实现流程

发送端

  • 创建 UDP 套接字:socket(AF_INET, SOCK_DGRAM, 0);
  • 开启广播权限:通过setsockopt设置SO_BROADCAST选项(核心步骤,不设置则无法发送广播包);
// 开启套接字的广播能力,必须在发送前设置inton=1;// 1为开启,0为关闭setsockopt(sockfd,SOL_SOCKET,SO_BROADCAST,&on,sizeof(on));
  • 填充广播地址结构体:目的 IP 设为广播地址(如255.255.255.255),目的端口与接收端一致;
  • 发送广播数据:调用sendto向广播地址发送数据包;
  • 关闭套接字:close(sockfd)

接收端

  • 创建 UDP 套接字;
  • 绑定本机 IP / 任意 IP(INADDR_ANY)和固定端口(需与发送端目的端口一致);
  • 调用recvfrom阻塞接收广播数据;
  • 关闭套接字

demo

  • receiver
#include<stdio.h>#include<sys/socket.h>#include<netinet/in.h>#include<netinet/ip.h>/* superset of previous */#include<unistd.h>#include<stdlib.h>#include<arpa/inet.h>#include<strings.h>#defineErrExit(msg)do{perror(msg);exit(EXIT_FAILURE);}while(0)typedefstructsockaddrAddr;typedefstructsockaddr_inAddr_in;intmain(intargc,char*argv[]){intfd=-1;Addr_in myaddr,peeraddr;socklen_tpeerlen=sizeof(peeraddr);charbuf[BUFSIZ]={};/*参数检查*/if(argc<3){fprintf(stderr,"%s<addr><port>",argv[0]);exit(EXIT_FAILURE);}/*创建套接字*/if((fd=socket(AF_INET,SOCK_DGRAM,0))<0)ErrExit("socket");/*设置通信结构体*/myaddr.sin_family=AF_INET;myaddr.sin_port=htons(atoi(argv[2]));if(!inet_aton(argv[1],&myaddr.sin_addr)){fprintf(stderr,"Invalid address\n");exit(EXIT_FAILURE);}/*绑定通信结构体*/if(bind(fd,(Addr*)&myaddr,sizeof(Addr_in)))ErrExit("bind");while(1){recvfrom(fd,buf,BUFSIZ,0,(Addr*)&peeraddr,&peerlen);printf("[%s:%d]%s\n",inet_ntoa(peeraddr.sin_addr),ntohs(peeraddr.sin_port),buf);}return0;}
  • send
#include<stdio.h>#include<sys/socket.h>#include<netinet/in.h>#include<netinet/ip.h>/* superset of previous */#include<unistd.h>#include<stdlib.h>#include<arpa/inet.h>#include<strings.h>#include<string.h>#defineErrExit(msg)do{perror(msg);exit(EXIT_FAILURE);}while(0)typedefstructsockaddrAddr;typedefstructsockaddr_inAddr_in;intmain(intargc,char*argv[]){intfd=-1;Addr_in peeraddr;socklen_tpeerlen=sizeof(peeraddr);charbuf[BUFSIZ]={};/*参数检查*/if(argc<3){fprintf(stderr,"%s<multiaddr><port>",argv[0]);exit(EXIT_FAILURE);}/*创建套接字*/if((fd=socket(AF_INET,SOCK_DGRAM,0))<0)ErrExit("socket");/*允许广播*/inton=1;setsockopt(fd,SOL_SOCKET,SO_BROADCAST,&on,sizeof(on));/*设置通信结构体*/peeraddr.sin_family=AF_INET;peeraddr.sin_port=htons(atoi(argv[2]));if(!inet_aton(argv[1],&peeraddr.sin_addr)){fprintf(stderr,"Invalid address\n");exit(EXIT_FAILURE);}while(1){fgets(buf,BUFSIZ,stdin);sendto(fd,buf,strlen(buf)+1,0,(Addr*)&peeraddr,peerlen);}return0;}

组播(多播)

核心概念

  • 组播是一对一组的精准传输:将数据包发送到指定的组播组,只有加入该组的主机才能接收数据包,未加入的主机无法感知
  • 仅 UDP 支持,组播数据包的源地址为单播地址,目的地址为专属组播地址
  • 相比广播,组播更节省网络带宽(避免无意义的全网发送),适用于需要精准一对多传输的场景(如视频直播、设备组网)

组播地址

  • 组播地址为 IP 地址中的D 类地址,与 A/B/C 类单播地址、E 类保留地址区分;
  • 地址范围:224.0.0.0 ~ 239.255.255.255;
  • 核心规则:一个 D 类地址对应一个唯一的组播组,组播地址仅能作为目的地址,不能作为源地址

核心结构体

  • 通过setsockopt设置IP_ADD_MEMBERSHIP选项时,需传入组播组配置结构体

ip_mreq(常用)

structip_mreq{structin_addrimr_multiaddr;/* 组播组的D类IP地址(如224.0.0.1) */structin_addrimr_interface;/* 本地网卡的IP地址,设为INADDR_ANY表示默认网卡 */};

ip_mreqn(含网卡编号,更精细)

structip_mreqn{structin_addrimr_multiaddr;/* 组播组的D类IP地址 */structin_addrimr_address;/* 本地接口的IP地址 */intimr_ifindex;/* 本地网卡的编号,设为0表示默认网卡 */};

实现流程

接收端

  • 创建 UDP 套接字:socket(AF_INET, SOCK_DGRAM, 0)
  • 填充组播结构体:设置组播组 IP、本地网卡 IP(默认INADDR_ANY)
  • 加入组播组:通过setsockopt设置IP_ADD_MEMBERSHIP选项(核心步骤,不加入则无法接收组播数据)
structip_mreqmreq;// 设置要加入的组播组IP(示例:224.0.0.1,局域网所有主机默认组)mreq.imr_multiaddr.s_addr=inet_addr("224.0.0.1");// 本地网卡IP,INADDR_ANY表示使用系统默认网卡mreq.imr_interface.s_addr=htonl(INADDR_ANY);// 加入组播组,级别为IPPROTO_IP,选项为IP_ADD_MEMBERSHIPif(setsockopt(fd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq))<0){perror("setsockopt");// 设置失败时打印错误exit(0);}
  • 绑定组播地址和端口:绑定的目的 IP 为组播组 D 类地址,端口与发送端一致
  • 接收组播数据:调用recvfrom阻塞接收
  • 关闭套接字:close(fd)

发送端

  • 发送端无需加入组播组,按 UDP 普通发送流程,仅需将目的 IP 设为组播组 D 类地址即可:
    • 创建 UDP 套接字
    • 填充目的地址结构体:目的 IP 为组播组地址,端口与接收端一致
    • 调用sendto发送组播数据
    • 关闭套接字

demo

  • receiver
#include<stdio.h>#include<sys/socket.h>#include<netinet/in.h>#include<netinet/ip.h>/* superset of previous */#include<unistd.h>#include<stdlib.h>#include<arpa/inet.h>#include<strings.h>#defineErrExit(msg)do{perror(msg);exit(EXIT_FAILURE);}while(0)typedefstructsockaddrAddr;typedefstructsockaddr_inAddr_in;intmain(intargc,char*argv[]){intfd=-1;Addr_in myaddr,peeraddr;socklen_tpeerlen=sizeof(peeraddr);structip_mreqnmreq;charbuf[BUFSIZ]={};/*参数检查*/if(argc<3){fprintf(stderr,"%s<addr><port>",argv[0]);exit(EXIT_FAILURE);}/*创建套接字*/if((fd=socket(AF_INET,SOCK_DGRAM,0))<0)ErrExit("socket");/*加入多播组*/bzero(&mreq,sizeof(mreq));if(!inet_aton(argv[1],&mreq.imr_multiaddr)){fprintf(stderr,"Invalid address\n");exit(EXIT_FAILURE);}if(setsockopt(fd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq))<0){perror("setsockopt");exit(0);}/*设置通信结构体*/myaddr.sin_family=AF_INET;myaddr.sin_port=htons(atoi(argv[2]));if(!inet_aton(argv[1],&myaddr.sin_addr)){fprintf(stderr,"Invalid address\n");exit(EXIT_FAILURE);}/*绑定通信结构体*/if(bind(fd,(Addr*)&myaddr,sizeof(Addr_in)))ErrExit("bind");while(1){recvfrom(fd,buf,BUFSIZ,0,(Addr*)&peeraddr,&peerlen);printf("[%s:%d]%s\n",inet_ntoa(peeraddr.sin_addr),ntohs(peeraddr.sin_port),buf);}return0;}
  • send
#include<stdio.h>#include<sys/socket.h>#include<netinet/in.h>#include<netinet/ip.h>/* superset of previous */#include<unistd.h>#include<stdlib.h>#include<arpa/inet.h>#include<strings.h>#include<string.h>#defineErrExit(msg)do{perror(msg);exit(EXIT_FAILURE);}while(0)typedefstructsockaddrAddr;typedefstructsockaddr_inAddr_in;intmain(intargc,char*argv[]){intfd=-1;Addr_in peeraddr;socklen_tpeerlen=sizeof(peeraddr);charbuf[BUFSIZ]={};/*参数检查*/if(argc<3){fprintf(stderr,"%s<multiaddr><port>",argv[0]);exit(EXIT_FAILURE);}/*创建套接字*/if((fd=socket(AF_INET,SOCK_DGRAM,0))<0)ErrExit("socket");/*设置通信结构体*/peeraddr.sin_family=AF_INET;peeraddr.sin_port=htons(atoi(argv[2]));if(!inet_aton(argv[1],&peeraddr.sin_addr)){fprintf(stderr,"Invalid address\n");exit(EXIT_FAILURE);}while(1){fgets(buf,BUFSIZ,stdin);sendto(fd,buf,strlen(buf)+1,0,(Addr*)&peeraddr,peerlen);}return0;}

广播 VS 组播

特性广播组播
传输范围局域网所有主机加入组播组的主机
地址类型网段广播地址 / 255.255.255.255D 类地址(224.0.0.0~239.255.255)
核心配置发送端开启SO_BROADCAST接收端加入IP_ADD_MEMBERSHIP
带宽占用高(全网发送)低(精准发送)
适用场景局域网全网通知(如设备发现)一对多精准传输(如直播、组播组网)
地址规则可使用通用广播地址一个 D 类地址对应一个组播组
http://www.jsqmd.com/news/401594/

相关文章:

  • 基于Agent实现智能客服:从架构设计到生产环境避坑指南
  • Agent实习模拟面试之vLLM:大模型推理加速的核心引擎与工程实践
  • 学长亲荐!一键生成论文工具,千笔AI VS 灵感ai
  • ChatTTS 对接实战:从零构建高可靠语音合成服务
  • 定稿前必看!千笔,抢手爆款的AI论文工具
  • ChatTTS案例实战:如何通过语音合成技术提升客服系统效率
  • Agent实习模拟面试之NL2SQL:从零构建自然语言到SQL的智能桥梁
  • Agent实习模拟面试之Benchmark:如何科学评估智能体的真实能力?
  • 深度测评 10个降AIGC软件:专科生降AI率必备工具全对比
  • 基于神经网络的毕设实战:从模型选型到部署落地的完整路径
  • ChatTTS 生产环境部署实战:从零搭建到高可用架构
  • ChatGPT内容转Word的高效实现:Python自动化方案与避坑指南
  • 【信息科学与工程学】【解决方案体系】 第二十篇 互联网行业收入和支出、利润抽成
  • 2026最新!王者级的降AI率工具 —— 千笔·专业降AI率智能体
  • 260219
  • 智能客服在金融领域的应用:从架构设计到生产环境避坑指南
  • n皇后算法
  • 一行代码实现数组去重与排序
  • AI专著撰写新突破!揭秘高效工具,轻松完成学术专著创作
  • 实测对比后AI论文工具,千笔AI VS speedai,研究生写作神器!
  • ChatTTS v3 技术解析:从语音合成原理到生产环境部署实战
  • ChatTTS Colab 实战:如何高效部署与优化语音合成工作流
  • AMD Windows平台下CosyVoice AI辅助开发实战:从环境配置到性能优化
  • 筑牢企业“防火墙”:奋飞咨询助力企业构建系统化反腐败体系 - 奋飞咨询ecovadis
  • AI 辅助开发实战:高效完成计算机毕业设计附源码的全流程指南
  • 2026年知名的环保家具板/耐磨防划家具板高评价直销厂家采购指南推荐(高评价) - 行业平台推荐
  • 微信客服API与飞书AI智能客服集成实战:从架构设计到避坑指南
  • Chatbot 内容动态添加实战:基于 Python 的模块化设计与实现
  • 2026年比较好的耐磨防划母婴板/高端定制母婴板哪家质量好厂家实力参考 - 行业平台推荐
  • 开源智能客服项目架构解析:从高并发设计到生产环境部署