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

Linux网络编程-UDP 组播原理与实战

一、UDP 组播核心概念

UDP 通信有三种典型模式,组播是单播和广播的中间形态,能精准向指定一组主机通信,大幅节省网络带宽:

通信模式特点适用场景
单播一对一(两台主机端对端通信)精准的点对点数据传输(如 TCP 连接、UDP 单主机通信)
广播一对所有(向局域网所有主机发数据)需局域网全量通知的场景(如 DHCP 地址分配)
组播一对一组(向特定主机组发数据)音视频流推送、多设备协同等场景

组播核心特性

  1. 一台主机可同时加入多个组播组;
  2. 组播既支持局域网通信,也可用于广域网(需路由器支持组播路由);
  3. 组播 / 广播属性默认关闭,需通过setsockopt()手动开启;
  4. 多播地址仅能作为目的地址,不能作为源地址(和广播地址特性一致);

二、IPv4 组播地址(D 类地址)

IP 组播通信依赖专属的 D 类 IP 地址,范围224.0.0.0 ~ 239.255.255.255,分为三类:

地址分类范围核心特点
局部链接多播地址224.0.0.0 ~ 224.0.0.255① 路由协议 / 特殊用途预留;② 路由器不转发;③ 仅局域网可用,不可用于公网
预留多播地址224.0.1.0 ~ 238.255.255.255① 用户可用的临时组地址;② 可用于 Internet 公网
管理权限多播地址239.0.0.0 ~ 239.255.255.255① 组织内部专用;② 类似私有 IP;③ 不可用于公网

三、UDP 组播代码实现

3.1 发送方(Sender.cpp)

核心要点

  • 无需绑定(bind)端口;
  • 目标地址使用组播地址(示例:224.0.0.88);
  • 循环发送组播数据,模拟持续推送场景。
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> int main(void) { char buf[BUFSIZ]; // 1. 创建UDP套接字 int sockfd = socket(AF_INET, SOCK_DGRAM, 0); if (-1 == sockfd) { perror("socket"); exit(1); } // 2. 配置组播目标地址(组播地址+端口) struct sockaddr_in peer; peer.sin_family = AF_INET; // IPv4协议 peer.sin_port = htons(9000); // 组播端口(需和接收方一致) peer.sin_addr.s_addr = inet_addr("224.0.0.88"); // 组播地址 printf("准备发送组播数据...\n"); // 3. 循环发送组播消息(模拟持续推送) for (int i = 1; ; i++) { sprintf(buf, "新年好,第 %d 次问候!", i); int ret = sendto(sockfd, buf, strlen(buf), 0, (struct sockaddr*)&peer, sizeof(peer)); printf("had send %d bytes: %s\n", ret, buf); sleep(1); // 每秒发送一次 } close(sockfd); // 实际循环不会执行到这里 return 0; }

3.2 接收方(Receiver.cpp)

核心要点

  • 必须绑定(bind)端口和INADDR_ANY地址;
  • 通过IP_ADD_MEMBERSHIP加入指定组播组;
  • 接收指定次数数据后,通过IP_DROP_MEMBERSHIP退出组播组;
  • 测试退出组播组后是否还能接收组播数据。
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> int main(void) { char buf[BUFSIZ]; // 1. 创建UDP套接字 int sockfd = socket(AF_INET, SOCK_DGRAM, 0); if (-1 == sockfd) { perror("socket"); exit(1); } // 2. 绑定端口(接收方必须bind) struct sockaddr_in addr; addr.sin_family = AF_INET; // IPv4协议 addr.sin_port = htons(9000); // 和发送方一致的组播端口 addr.sin_addr.s_addr = INADDR_ANY; // 接收本机所有网卡的组播数据 int ret = bind(sockfd, (struct sockaddr*)&addr, sizeof(addr)); if (-1 == ret) { perror("bind"); exit(1); } // 3. 配置组播组信息(要加入的组播地址+本地网卡) struct ip_mreq req; req.imr_multiaddr.s_addr = inet_addr("224.0.0.88"); // 要加入的组播地址 req.imr_interface.s_addr = INADDR_ANY; // 本机所有网卡 // 4. 加入组播组 ret = setsockopt( sockfd, IPPROTO_IP, // IP层协议 IP_ADD_MEMBERSHIP, // 加入组播组的选项 &req, sizeof(req)); if (ret < 0) { perror("setsockopt(IP_ADD_MEMBERSHIP)"); exit(1); } // 5. 接收10次组播数据(加入组播组期间) printf("已加入组播组,开始接收数据...\n"); for(int i=0; i<10; i++) { struct sockaddr_in from; socklen_t len = sizeof(from); ret = recvfrom(sockfd, buf, sizeof(buf), 0, (struct sockaddr*)&from, &len); printf("【加入组播组】recv from: %s:%d -> %s\n", inet_ntoa(from.sin_addr), ntohs(from.sin_port), buf); } // 6. 退出组播组 ret = setsockopt( sockfd, IPPROTO_IP, IP_DROP_MEMBERSHIP, // 退出组播组的选项 &req, sizeof(req)); if (ret < 0) { perror("setsockopt(IP_DROP_MEMBERSHIP)"); exit(1); } // 7. 测试退出组播组后是否能接收数据(理论上收不到) printf("已退出组播组,尝试接收数据...\n"); for(int i=0; i<10; i++) { struct sockaddr_in from; socklen_t len = sizeof(from); ret = recvfrom(sockfd, buf, sizeof(buf), 0, (struct sockaddr*)&from, &len); printf("【退出组播组】recv from: %s:%d -> %s\n", inet_ntoa(from.sin_addr), ntohs(from.sin_port), buf); } close(sockfd); return 0; }

四、编译与测试

4.1 编译命令

# 编译发送方 g++ Sender.cpp -o sender # 编译接收方 g++ Receiver.cpp -o receiver

4.2 测试步骤

  1. 启动接收方:在 1 台或多台同一局域网的主机上执行接收程序
    ./receiver
  2. 启动发送方:在任意主机执行发送程序
    ./sender
  3. 观察结果
    • 接收方前 10 次能正常收到组播数据;
    • 退出组播组后,后续无法接收组播数据(recvfrom 会阻塞)。

总结

  1. UDP 组播是 “一对一组” 通信,相比广播能大幅节省带宽,支持局域网 / 广域网使用;
  2. 组播依赖 IPv4 D 类地址(224.0.0.0~239.255.255.255),不同段地址有不同使用范围;
  3. 组播接收方必须 bind 端口,且需通过IP_ADD_MEMBERSHIP加入组播组,退出需用IP_DROP_MEMBERSHIP,发送方无需 bind 仅需指定组播地址。
http://www.jsqmd.com/news/240636/

相关文章:

  • 深入解析 VPC:云端网络架构的核心基石
  • 基于STM3251单片机的多功能垃圾桶控制系统(程序源码+实物+原理图+PCB+论文+答辩稿)
  • Linux命令创意组合大赛技术文章大纲组合的灵活性和强大功能
  • 基于AI的智能化学术写作流程,7个平台集成格式规范验证与LaTeX模板库功能
  • 基于STM3251单片机的两轮平衡车设计(程序源码+实物+原理图+PCB+论文+答辩稿)
  • 子数列求积【牛客tracker 每日一题】
  • 超越想象:揭秘外星飞碟的“零质量”飞行与时空操控技术
  • SecurityBridge宣布首席执行官更迭,以加速全球扩张
  • 结合AI高效完成科研论文写作,这7个网站支持自定义格式与LaTeX模板导出
  • Lenovo为零售业提供实时门店可视化与人工智能支持,实现运行首日即创造价值
  • MRM Health获美国FDA新药临床试验申请(IND)批准,启动MH002治疗轻中度溃疡性结肠炎的2b期临床试验
  • 【开题答辩全过程】以 基于安卓的点餐系统的设计与实现为例,包含答辩的问题和答案
  • 基于STM3251单片机的Nb-IoT图书馆座位智能管理系统(程序源码+实物+原理图+PCB+论文+答辩稿)
  • 通过人工智能快速生成高质量论文,推荐7个提供格式规范及LaTeX兼容的实用网站
  • 【开题答辩全过程】以 基于springbootvue图书馆选座系统设计与实现为例,包含答辩的问题和答案
  • Magna AI加入NVIDIA Inception计划,推动生产级人工智能规模化发展
  • 基于AI的智能论文生成方案,7个资源网站包含格式规范检查和LaTeX系统适配
  • RAG到RGA:生成式AI的范式演进
  • 基于STM32的养殖场环境检测系统(程序源码+实物+原理图+PCB+论文+答辩稿)
  • 基于微信小程序的博物馆文创系统的设计与实现PHP_nodejs_vue+uniapp
  • 怎么才能把短视频中文配音变成英文配音?
  • 基于STM32的智能宠物喂养系统设计(程序源码+实物+原理图+PCB+论文+答辩稿)
  • 通过AI驱动的论文创作工具,7个平台能自动处理LaTeX代码与学术格式调整
  • 基于微信小程序的咖啡店饮品点餐系统必吃榜PHP_nodejs_vue+uniapp
  • 基于STM32的自动输液检测系统设计(程序源码+实物+原理图+PCB+论文+答辩稿)
  • 销售额飙涨 2.5 倍,TACOS 直降 10 点!DeepBI 助力亚马逊卖家高效破局
  • 基于微信小程序的地方特色农产品交易的设计与实现--论文PHP_nodejs_vue+uniapp
  • 基于STM32设计的老人监控系统设计(程序源码+实物+原理图+PCB+论文+答辩稿)
  • 基于微信小程序的大学生就业管理系统 人才求职招聘系统PHP_nodejs_vue+uniapp
  • 每日 AI 评测速递来啦(1.13)