UDP 多点通信

一、setsockopt/getsockopt 函数详解

1. 函数原型

c

#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);

2. 功能
  • setsockopt:设置套接字选项(修改网络属性)。
  • getsockopt:获取套接字选项(查询网络属性)。
3. 参数说明
参数描述
sockfd套接字文件描述符
level协议层级:
SOL_SOCKET(通用选项)
IPPROTO_IP(IP 层选项)
IPPROTO_UDP(UDP 层选项)
optname选项名称(依赖于level
optval选项值(指针类型,具体类型取决于optname
optlenoptval的字节长度(getsockopt需传入指针,setsockopt需传入值)
4. 常用选项及示例
4.1 SOL_SOCKET 层级
  • SO_REUSEADDR:允许重用本地地址和端口(解决端口占用问题)。

    c

    int optval = 1;
    setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
    
  • SO_BROADCAST:允许发送广播数据(仅 UDP 可用)。

    c

    int optval = 1;
    setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(optval)); // 发送方需设置
    
  • SO_RCVTIMEO/SO_SNDTIMEO:设置接收 / 发送超时时间(struct timeval类型)。

    c

    struct timeval timeout = {3, 0}; // 3秒超时
    setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
    
4.2 IPPROTO_IP 层级(组播相关)
  • IP_ADD_MEMBERSHIP:加入组播组。

    c

    struct ip_mreqn mreq;
    mreq.imr_multiaddr.s_addr = inet_addr("224.1.2.3"); // 组播IP
    mreq.imr_address.s_addr = inet_addr("192.168.1.100"); // 本地IP
    mreq.imr_ifindex = 0; // 网络接口索引(0表示自动选择)
    setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
    
  • IP_DROP_MEMBERSHIP:退出组播组(参数同IP_ADD_MEMBERSHIP)。
4.3 IPPROTO_TCP 层级
  • TCP_NODELAY:禁用 Nagle 算法(提升实时性)。

    c

    int optval = 1;
    setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &optval, sizeof(optval));
    

二、UDP 多点通信

1. 广播通信(Broadcast)
  • 特点

    • 一对多通信,数据发送到局域网内所有主机。
    • 广播地址示例:192.168.1.255(网络号 + 全 1 主机号)或255.255.255.255(受限广播)。
    • 仅 UDP 支持,数据不可跨路由器。
  • 实现步骤

    广播接收者(UDP 服务器)
    1. 创建 UDP 套接字:socket(AF_INET, SOCK_DGRAM, 0)
    2. 绑定广播地址(如192.168.1.2550.0.0.0)。

      c

      struct sockaddr_in addr;
      addr.sin_family = AF_INET;
      addr.sin_port = htons(8888);
      addr.sin_addr.s_addr = inet_addr("192.168.1.255");
      bind(sockfd, (struct sockaddr*)&addr, sizeof(addr));
      
    3. 接收数据:recvfrom()
    广播发送者(UDP 客户端)
    1. 创建 UDP 套接字。
    2. 设置SO_BROADCAST选项。
    3. 发送数据到广播地址:sendto()

      c

      int optval = 1;
      setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(optval));
      struct sockaddr_in dest_addr;
      dest_addr.sin_family = AF_INET;
      dest_addr.sin_port = htons(8888);
      dest_addr.sin_addr.s_addr = inet_addr("192.168.1.255");
      sendto(sockfd, "Hello", 5, 0, (struct sockaddr*)&dest_addr, sizeof(dest_addr));
      
2. 组播通信(Multicast)
  • 特点

    • 一对一组通信,仅加入组播组的主机可接收数据。
    • 组播 IP 范围:224.0.0.0~239.255.255.255
    • 需通过IP_ADD_MEMBERSHIP加入组播组。
  • 实现步骤

    组播接收者(UDP 服务器)
    1. 创建 UDP 套接字。
    2. 加入组播组:setsockopt()设置IP_ADD_MEMBERSHIP
    3. 绑定组播 IP 和端口(或绑定0.0.0.0接收所有组播数据)。

      c

      struct ip_mreqn mreq;
      mreq.imr_multiaddr.s_addr = inet_addr("224.1.2.3");
      mreq.imr_address.s_addr = INADDR_ANY; // 本地IP设为任意
      setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
      struct sockaddr_in addr;
      addr.sin_family = AF_INET;
      addr.sin_port = htons(8888);
      addr.sin_addr.s_addr = INADDR_ANY; // 绑定任意IP
      bind(sockfd, (struct sockaddr*)&addr, sizeof(addr));
      
    组播发送者(UDP 客户端)
    1. 创建 UDP 套接字。
    2. 直接发送数据到组播 IP:sendto()

      c

      struct sockaddr_in dest_addr;
      dest_addr.sin_family = AF_INET;
      dest_addr.sin_port = htons(8888);
      dest_addr.sin_addr.s_addr = inet_addr("224.1.2.3");
      sendto(sockfd, "Hello", 5, 0, (struct sockaddr*)&dest_addr, sizeof(dest_addr));
      

三、关键对比

特性广播(Broadcast)组播(Multicast)
地址范围局域网内所有主机(如192.168.1.255组播组(如224.1.2.3
网络层支持依赖链路层广播依赖 IP 组播协议
跨路由不可跨路由可通过配置跨路由(需路由器支持)
资源消耗高(所有主机接收)低(仅组成员接收)
适用场景局域网内通知(如 DHCP)实时流媒体、在线会议(如视频直播)

四、代码示例:UDP 广播聊天

1. 广播接收者(服务器)

c

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>#define PORT 8888
#define BUF_SIZE 128int main() {// 创建UDP套接字int sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (sockfd < 0) { perror("socket error"); return -1; }// 允许端口重用int optval = 1;setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));// 绑定广播地址struct sockaddr_in addr;memset(&addr, 0, sizeof(addr));addr.sin_family = AF_INET;addr.sin_port = htons(PORT);addr.sin_addr.s_addr = inet_addr("192.168.1.255"); // 或 INADDR_BROADCASTif (bind(sockfd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {perror("bind error"); return -1;}// 接收广播数据char buf[BUF_SIZE] = {0};struct sockaddr_in cli_addr;socklen_t cli_len = sizeof(cli_addr);while (1) {ssize_t n = recvfrom(sockfd, buf, BUF_SIZE-1, 0, (struct sockaddr*)&cli_addr, &cli_len);if (n > 0) {buf[n] = '\0';printf("Received: %s\n", buf);}}close(sockfd);return 0;
}
2. 广播发送者(客户端)

c

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>#define PORT 8888
#define BUF_SIZE 128int main() {// 创建UDP套接字int sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (sockfd < 0) { perror("socket error"); return -1; }// 允许发送广播int optval = 1;setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(optval));// 广播地址struct sockaddr_in dest_addr;memset(&dest_addr, 0, sizeof(dest_addr));dest_addr.sin_family = AF_INET;dest_addr.sin_port = htons(PORT);dest_addr.sin_addr.s_addr = inet_addr("192.168.1.255");// 发送数据char buf[BUF_SIZE] = {0};while (fgets(buf, BUF_SIZE, stdin)) {buf[strcspn(buf, "\n")] = 0; // 去除换行符sendto(sockfd, buf, strlen(buf), 0, (struct sockaddr*)&dest_addr, sizeof(dest_addr));memset(buf, 0, BUF_SIZE);}close(sockfd);return 0;
}

五、总结

  • setsockopt/getsockopt:是网络编程中配置套接字行为的核心函数,通过不同层级和选项可实现端口重用、超时控制、组播加入等高级功能。
  • UDP 广播:适用于局域网内的一对多通信,但存在广播风暴风险,且无法跨路由。
  • UDP 组播:通过组播组实现高效的一对多通信,节省网络资源,适合实时数据传输。
  • 注意事项
    • 广播发送方需设置SO_BROADCAST选项,接收方需绑定广播地址。
    • 组播接收方需通过IP_ADD_MEMBERSHIP加入组播组,发送方直接向组播 IP 发送数据。

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

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

相关文章

说一说Node.js高性能开发中的I/O操作

众所周知&#xff0c;在软件开发的领域中&#xff0c;输入输出&#xff08;I/O&#xff09;操作是程序与外部世界交互的重要环节&#xff0c;比如从文件读取数据、向网络发送请求等。这段时间&#xff0c;也指导项目中一些项目的开发工作&#xff0c;发现在Node.js运用中&#…

Charles抓包并破解ProtoBuf请求

安装Charles并抓包 如果是外网的需要root安装一系列证书等&#xff0c;详细见参考文章&#xff1a; 在雷电模拟器安卓7.0上使用Charles抓包详细教程 遇到如下问题&#xff1a; 1.粘贴到目录/system/etc/security/cacerts内&#xff0c;粘贴不了。需要打开这个 2.模拟器wifi打…

Odoo 18 安全组与访问权限管理指南

Odoo 18 安全组与访问权限管理指南 一、准备工作&#xff1a;在自定义模块中创建安全配置文件 创建 security 文件夹 在自定义模块内创建名为 security 的文件夹&#xff0c;用于存放安全组和访问权限的定义文件。 二、定义模型访问权限&#xff1a;ir.model.access.csv 文…

使用lldb查看Rust不同类型的结构

目录 前言 正文 标量类型 复合类型——元组 复合类型——数组 函数 &str struct 可变数组vec Iter String Box Rc Arc RefCell Mutex RwLock Channel 总结 前言 笔者发现这个lldb挺好玩的&#xff0c;可以查看不同类型的结构&#xff0c;虽然这好像是C的东…

uniapp使用ui.request 请求流式输出

正文&#xff1a; 在现代Web开发中&#xff0c;实时数据流和长时间运行的请求变得越来越常见&#xff0c;尤其是在处理大量数据或进行实时通信时。在这种情况下&#xff0c;uniapp 提供的 ui.request 请求方法可以帮助我们轻松实现流式输出请求。本文将介绍如何使用 uni.reques…

如何恢复被勒索软件加密的服务器文件(解密与备份策略)

针对勒索软件加密文件的恢复和解密策略&#xff0c;结合当前数据安全最佳实践&#xff0c;整理应对指南如下&#xff1a; 一、文件解密与修复方法 立即隔离设备‌ 断开网络连接并禁用共享功能&#xff0c;防止病毒横向传播 通过文件后缀异常&#xff08;如.locked、.wxx&…

JS,ES,TS三者什么区别

Java Script(JS)、ECMAScript(ES)、TypeScript(TS) 的核心区别与关联的详细解析,结合技术背景、设计目标及应用场景展开说明: 一、核心定义与关系 JavaScript(JS) 定义:一种动态类型、基于原型的脚本语言,由 Netscape 公司于 1995 年首次开发,用于网页交互功能。角…

【MapReduce入门】深度解析MapReduce:定义、核心特点、优缺点及适用场景

目录 1 什么是MapReduce&#xff1f; 2 MapReduce的核心特点 2.1 分布式处理 2.2 容错机制 3 MapReduce的完整工作流程 4 MapReduce的优缺点分析 4.1 优势 4.2 局限性 5 MapReduce典型应用场景 5.1 适用场景 5.2 不适用场景 6 MapReduce与其他技术的对比 7 总结 1…

【Redis】分布式锁的实现

目录 一、本地锁存在的问题 二、redis实现分布式锁原理 三、使用示例 四、锁误删问题 解决思路 获取锁和释放锁代码优化 五、锁释放的原子性问题 解决思路&#xff08;Lua脚本&#xff09; 使用流程 总结 大家好&#xff0c;我是千语。上期给大家讲了使用悲观锁来解决…

Unity3D对象池设计与实现详解

前言 在Unity3D中&#xff0c;对象池&#xff08;Object Pooling&#xff09;是一种优化技术&#xff0c;用于减少频繁实例化和销毁对象带来的性能开销。以下是对象池的详细设计和实现步骤&#xff1a; 对惹&#xff0c;这里有一个游戏开发交流小组&#xff0c;希望大家可以点…

[Spring]-组件的生命周期

组件生命周期 认识组件的声明周期 实验1 通过Bean指定组件的生命周期 package com.guigu.spring.ioc.bean;Data public class User {private String username;private String password;private Car car;Autowiredpublic void setCar(Car car) {System.out.println("自动…

【golang】网络数据包捕获库 gopacket

详解 github.com/google/gopacket/pcap 包 github.com/google/gopacket/pcap 是 Go 语言中一个强大的网络数据包捕获库&#xff0c;它是 gopacket 项目的一部分&#xff0c;提供了对 libpcap&#xff08;Linux/Unix&#xff09;和 WinPcap&#xff08;Windows&#xff09;的 G…

RBTree的模拟实现

1&#xff1a;红黑树的概念 红⿊树是⼀棵⼆叉搜索树&#xff0c;他的每个结点增加⼀个存储位来表⽰结点的颜⾊&#xff0c;可以是红⾊或者⿊⾊。通过对任何⼀条从根到叶⼦的路径上各个结点的颜⾊进⾏约束&#xff0c;红⿊树确保没有⼀条路径会⽐其他路径⻓出2倍&#xff0c;因…

React 第三十九节 React Router 中的 unstable_usePrompt Hook的详细用法及案例

React Router 中的 unstable_usePrompt 是一个用于在用户尝试离开当前页面时触发确认提示的自定义钩子&#xff0c;常用于防止用户误操作导致数据丢失&#xff08;例如未保存的表单&#xff09;。 一、unstable_usePrompt用途 防止意外离开页面&#xff1a;当用户在当前页面有…

OSI 7层模型

OSI 7层模型&#xff1a; 1、物理层&#xff08;光纤等把电脑连接起来的物理手段&#xff09; 2、数据链路层&#xff08;以太网&#xff0c;确认0和1电信号的分组方式&#xff0c;负责MAC地址&#xff0c;MAC地址用于在网络中唯一标示一个网卡&#xff0c;相当于网卡的身份证…

视频编解码学习十一之视频原始数据

一、视频未编码前的原始数据是怎样的&#xff1f; 视频在未编码前的原始数据被称为 原始视频数据&#xff08;Raw Video Data&#xff09;&#xff0c;主要是按照帧&#xff08;Frame&#xff09;来组织的图像序列。每一帧本质上就是一张图片&#xff0c;通常采用某种颜色格式…

Redis学习打卡-Day1-SpringDataRedis、有状态无状态

Redis的Java客户端 Jedis 以 Redis 命令作为方法名称&#xff0c;学习成本低&#xff0c;简单实用。Jedis 是线程不安全的&#xff0c;并且频繁的创建和销毁连接会有性能损耗&#xff0c;因此推荐使用 Jedis 连接池代替Jedis的直连方式。 lettuce Lettuce是基于Netty实现的&am…

告别静态配置!Spring Boo动态线程池实战指南:Nacos+Prometheus全链路监控

一、引言 1.1 动态线程池的必要性 传统线程池的参数&#xff08;如核心线程数、队列容量&#xff09;通常通过配置文件静态定义&#xff0c;无法根据业务负载动态调整。例如&#xff0c;在电商大促场景中&#xff0c;流量可能瞬间激增&#xff0c;静态线程池容易因配置不合理导…

Flask如何读取配置信息

目录 一、使用 app.config 读取配置 二、设置配置的几种方式 1. 直接设置 2. 从 Python 文件加载 3. 从环境变量加载 4. 从字典加载 5. 从 .env 文件加载&#xff08;推荐开发环境用&#xff09; 三、读取配置值 四、最佳实践建议 在 Flask 中读取配置信息有几种常见方…

【React中useCallback钩子详解】

useCallback 是 React 中的一个性能优化 Hook,用于缓存函数引用,避免在组件重新渲染时重复创建相同的函数,从而减少不必要的子组件渲染或副作用执行。以下是其核心要点: 1. 核心作用 函数记忆化:返回一个记忆化的回调函数,仅在依赖项变化时重新创建函数,否则复用之前的函…