Linux网络编程系列之UDP广播

Linux网络编程系列  (够吃,管饱)

        1、Linux网络编程系列之网络编程基础

        2、Linux网络编程系列之TCP协议编程

        3、Linux网络编程系列之UDP协议编程

        4、Linux网络编程系列之UDP广播

        5、Linux网络编程系列之UDP组播

        6、Linux网络编程系列之服务器编程——阻塞IO模型

        7、Linux网络编程系列之服务器编程——非阻塞IO模型

        8、Linux网络编程系列之服务器编程——多路复用模型

        9、Linux网络编程系列之服务器编程——信号驱动模型

一、什么是UDP广播

       UDP广播是一种网络通信的方式,在广域网或局域网中,UDP广播可以向多个目标主机发送数据包,使得网络中的所有设备都能接收到广播消息。一定是采用UDP协议。

二、特性

        1、面向无连接:UDP广播不需要建立连接,可以直接发送数据包到目标设备。

        2、广播特性UDP广播可以向一个网络中的所有设备发送数据包。

        3、不可靠性:UDP广播发送的数据包无法保证传输的可靠性,可能会发生数据丢失、错误等情况。

        4、速度快、开销小:UDP广播不需要建立连接,因此传输速度快,开销小,适用于实时流媒体传输等应用场景。

        5、 安全性较低:UDP广播发送的数据包可以被网络中的其他设备接收,可能会存在数据泄露的风险。

        6、适用于广播通信场景:UDP广播适用于需要向网络中所有设备发送数据的场景,比如寻找可用设备传输实时视频或音频数据等。

三、使用场景

        UDP广播主要用于数据的实时传输和设备的发现,常见的应用场景包括:

        1、视频和音频的实时传输:UDP广播可以使得多个设备同时接收到同一流的数据,实现实时的视频会议和音频播放等功能。

        2、网络打印机的自动发现:通过UDP广播,打印机可以向网络中广播自己的存在,从而被所有的设备发现和使用。

        3、多人游戏的联机:UDP广播可以将游戏数据同时发送给所有玩家的设备,实现多人游戏的联机功能。

        4、网络摄像头的实时监控:通过UDP广播,摄像头可以将实时的视频流发送给所有监控软件,使得监控人员能够同时查看视频。

四、UDP广播通信流程

        1、发送方(不一定是服务器或者客户端)

        (1)、建立套接字。使用socket()

        (2)、设置套接字属性为广播。使用setsockopt()

        (3)、绑定自己的IP地址和端口号。使用bind()(可以省略)

        (4)、发送数据,并指定接收方为广播地址。使用sendto()

        (5)、关闭套接字

        2、接收方(不一定是服务器或者客户端)

        (1)、建立套接字。使用socket()

        (2)、设置端口复用。使用setsockopt()(可选,推荐)

        (3)、绑定IP地址为广播地址和端口号。使用bind()(不可以省略)

        (4)、接收数据。使用recvfrom()

        (5)、关闭套接字

五、相关函数API

   1、建立套接字

// 建立套接字 
int socket(int domain, int type, int protocol);// 接口说明返回值:成功返回一个套接字文件描述符,失败返回-1参数domain:用来指定使用何种地址类型,有很多,具体看别的资源(1)PF_INET 或者 AF_INET 使用IPV4网络协议(2)其他很多的,看别的资源参数type:通信状态类型选择,有很多,具体看别的资源(1)SOCK_STREAM    提供双向连续且可信赖的数据流,即TCP(2)SOCK_DGRAM     使用不连续不可信赖的数据包连接,即UDP参数protocol:用来指定socket所使用的传输协议编号,通常不用管,一般设为0

           2、设置端口状态

// 设置端口的状态
int setsockopt(int sockfd, int level, int optname,const void *optval, socklen_t optlen);// 接口说明返回值:成功返回0,失败返回-1参数sockfd:待设置的套接字参数level: 待设置的网络层,一般设成为SOL_SOCKET以存取socket层参数optname:待设置的选项,有很多种,具体看别的资源,这里讲常用的(1)、SO_REUSEADDR    允许在bind()过程中本地地址可复用,即端口复用(2)、SO_BROADCAST    使用广播的方式发送,通常用于UDP广播(3)、SO_SNDBUF       设置发送的暂存区大小(4)、SO_RCVBUF       设置接收的暂存区大小参数optval:待设置的值参数optlen:参数optval的大小,即sizeof(optval)

          3、绑定IP地址和端口号

// 绑定自己的IP地址和端口号int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);// 接口说明返回值:参数sockfd:待绑定的套接字参数addrlen:参数addr的大小,即sizeof(addr)参数addr:IP地址和端口的结构体,通用的结构体,根据sockfd的类型有不同的定义当sockfd的domain参数指定为IPV4时,结构体定义为struct sockaddr_in{unsigned short int sin_family;    // 需与sockfd的domain参数一致uint16_t sin_port;            // 端口号struct in_addr sin_addr;      // IP地址 unsigned char sin_zero[8];    // 保留的,未使用};struct in_addr{uin32_t s_addr;}
// 注意:网络通信时,采用大端字节序,所以端口号和IP地址需要调用专门的函数转换成网络字节序

           4、字节序转换接口 

// 第一组接口
// 主机转网络IP地址,输入主机IP地址
uint32_t htonl(uint32_t hostlong);// 主机转网络端口,输入主机端口号
uint16_t htons(uint16_t hostshort);    // 常用// 网络转主机IP,输入网络IP地址
uint32_t ntohl(uint32_t netlong);// 网络转主机端口,输入网络端口
uint16_t ntohs(uint16_t netshort);// 第二组接口,只能用于IPV4转换,IP地址
// 主机转网络
int inet_aton(const char *cp, struct in_addr *inp);// 主机转网络
in_addr_t inet_addr(const char *cp);    // 常用// 网络转主机
int_addr_t inet_network(const char *cp);// 网络转主机
char *inet_ntoa(struct in_addr in);    // 常用

          5、发送数据

// UDP协议发送数据
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);// 接口说明返回值:成功返回成功发送的字节数,失败返回-1参数sockfd:发送者的套接字参数buf:发送的数据缓冲区参数len:发送的长度参数flags:一般设置为0,还有其他数值,具体查询别的资源参数dest_addr:接收者的网络地址参数addrlen:接收者的网络地址大小,即sizeof(dest_addr)

           6、接收数据

// UDP协议接收数据
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);// 接口说明:返回值:成功返回成功接收的字节数,失败返回-1参数sockfd:接收者的套接字参数buf:接收数据缓的冲区参数len:接收的最大长度参数flags:一般设置为0,还有其他数值,具体查询别的资源参数src_addr:发送者的网络地址,可以设置为NULL参数addrlen:  发送者的网络地址大小,即sizeof(src_addr)

          7、关闭套接字

// 关闭套接字
int close(int fd);// 接口说明返回值:成功返回0,失败返回-1参数fd:套接字文件描述符

六、案例

        实现UDP广播的演示

        发送方BroadcastSend.c

// UDP广播发送方的案例#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>       
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>#define SEND_IP   "192.168.64.128"    // 记得改为自己IP
#define SEND_PORT 10000   // 不能超过65535,也不要低于1000,防止端口误用int main(int argc, char *argv[])
{// 1、建立套接字,使用IPV4网络地址,UDP协议int sockfd = socket(AF_INET, SOCK_DGRAM, 0);if(sockfd == -1){perror("socket fail");return -1;}// 2、设置套接字为广播属性int optval = 1; // 这里设置套接字为广播属性,所以随便写一个值int ret = setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(optval));if(ret == -1){perror("setsockopt fail");close(sockfd);return -1;}// 3、绑定自己的IP地址和端口号(可以省略)struct sockaddr_in send_addr = {0};socklen_t addr_len = sizeof(struct sockaddr);send_addr.sin_family = AF_INET;   // 指定协议为IPV4地址协议send_addr.sin_port = htons(SEND_PORT);  // 端口号send_addr.sin_addr.s_addr = inet_addr(SEND_IP); // IP地址ret = bind(sockfd, (struct sockaddr*)&send_addr, addr_len);if(ret == -1){perror("bind fail");close(sockfd);return -1;}// 4、发送数据uint16_t port = 0;  // 端口号char ip[20] = {0};  // IP地址struct sockaddr_in recv_addr = {0};char msg[128] = {0};    // 数据缓冲区// 注意输入广播地址,格式为*.*.*.255printf("please input receiver IP and port\n");scanf("%s %hd", ip, &port);printf("IP = %s, port = %hd\n", ip, port);recv_addr.sin_family = AF_INET;   // 指定用IPV4地址recv_addr.sin_port = htons(port); // 接收者的端口号recv_addr.sin_addr.s_addr = inet_addr(ip);    // 接收者的IP地址while(getchar() != '\n');   // 清空多余的换行符while(1){printf("please input data:\n");fgets(msg, sizeof(msg)/sizeof(msg[0]), stdin);// 发送数据,注意要填写接收者的地址ret = sendto(sockfd, msg, strlen(msg), 0, (struct sockaddr*)&recv_addr, addr_len);if(ret > 0){printf("success: send %d bytes\n", ret);}}// 5、关闭套接字close(sockfd);return 0;
}

        接收方BroadcastRecv.c 

// UDP广播接收方的案例#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>       
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>#define RECV_IP   "192.168.64.255"    // 记得改为广播地址
#define RECV_PORT 20000   // 不能超过65535,也不要低于1000,防止端口误用int main(int argc, char *argv[])
{// 1、建立套接字,使用IPV4网络地址,UDP协议int sockfd = socket(AF_INET, SOCK_DGRAM, 0);if(sockfd == -1){perror("socket fail");return -1;}// 2、设置端口复用(推荐)int optval = 1; // 这里设置为端口复用,所以随便写一个值int ret = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));if(ret == -1){perror("setsockopt fail");close(sockfd);return -1;}// 3、绑定自己的IP地址和端口号(不可以省略)struct sockaddr_in recv_addr = {0};socklen_t addr_len = sizeof(struct sockaddr);recv_addr.sin_family = AF_INET;   // 指定协议为IPV4地址协议recv_addr.sin_port = htons(RECV_PORT);  // 端口号// recv_addr.sin_addr.s_addr = inet_addr(RECV_IP); // IP地址. 写下面的更好recv_addr.sin_addr.s_addr = htonl(INADDR_ANY);  // 本机内所有的IP地址ret = bind(sockfd, (struct sockaddr*)&recv_addr, addr_len);if(ret == -1){perror("bind fail");close(sockfd);return -1;}// 4、接收数据uint16_t port = 0;  // 端口号char ip[20] = {0};  // IP地址struct sockaddr_in send_addr = {0};char msg[128] = {0};    // 数据缓冲区while(1){// 接收数据,注意使用发送者的地址来接收ret = recvfrom(sockfd, msg, sizeof(msg)/sizeof(msg[0]), 0, (struct sockaddr*)&send_addr, &addr_len);if(ret > 0){memset(ip, 0, sizeof(ip));  // 先清空IPstrcpy(ip, inet_ntoa(send_addr.sin_addr));    // 网络IP转主机IPport = ntohs(send_addr.sin_port); // 网络端口号转主机端口号printf("[%s:%d] send data: %s\n", ip, port, msg);memset(msg, 0, sizeof(msg));    // 清空数据区}}// 5、关闭套接字close(sockfd);return 0;
}

        通信演示

        注:第一幅图由于只有一台电脑不太好演示广播效果,第二幅图用了一台电脑和一个开发板。

七、总结

        UDP广播一定是采用UDP协议的,通信流程跟UDP协议的通信流程差不多,就是要注意设置发送方套接字属性为广播,然后设置接收方的IP地址为广播地址,UDP广播主要用于数据的实时传输和设备的发现。

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

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

相关文章

【linux】日志和journalctl 管理查看日志

目录 既看即用 简略介绍 linux的日志类型 系统日志 介绍 区别的简单说明 区别的详细说明 journalctl是什么&#xff1f;&#xff08;查看系统日志的工具&#xff09; 详细内容 linux的日志类型 systemd日志&#xff08;systemd-journald&#xff09; 放在哪个目录 …

(C++ STL) 详解vector模拟实现

目录 一.vector的介绍 1.vector的介绍 二.vector的定义模拟实现 三.vector各接口的模拟实现 1.vector迭代器的模拟实现 2.构造函数 2.1无参构造 2.2 n个val构造 2.3迭代器区间构造 2.4通过对象初始化&#xff08;拷贝构造&#xff09; 3.析构函数 4.size 5.operato…

RabbitMQ清除积压消息/管理界面出现 Unacked 消息

1.问题&#xff1a; rabbitmq的生产者端循环产生了多条消息给消费者&#xff0c;而消费者无法及时将消息处理掉&#xff0c;在消费端积压了多条消息&#xff08;消费失败的时候&#xff0c;消息队列会一直重复的发送消息&#xff0c;导致程序死循环&#xff09;需要清理项目因为…

寻找可靠的软件外包开发公司

寻找可靠的软件外包开发公司是关键&#xff0c;以确保项目的顺利交付和质量。以下是一些方法和步骤&#xff0c;帮助您找到可靠的软件外包开发公司&#xff0c;希望对大家有所帮助。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0c;欢迎交流合作。 明确…

linux 学习:查找命令 find | grep

作者: 苏丙榅 原文链接: https://subingwen.cn/linux/commpress/ 在使用Linux系统的时候, 我们经常会需要查找某些文件&#xff0c;但是大多数情况下我们并不能确定这些文件的具体位置&#xff0c;这样的话就非常浪费我们的时间。Linux为我们提供了很多的用于文件搜索的命令, 如…

【Eclipse】安装与卸载教程

目录 1.绿色版免安装版本 2.安装版本 3.卸载 首先打开官网&#xff1a;Eclipse Downloads | The Eclipse Foundation 选择download package 如图所示&#xff0c;到如下界面 1.绿色版免安装版本 按图片点击&#xff0c;即可开始下载 下载好后解压 &#xff0c;在桌面创建…

LeetCode24.两两交换链表中的节点

这道题还是比较简单&#xff0c;我看完题目的想法就是借助一个第三变量&#xff0c;来改变两个节点的指针的指向&#xff0c;比如我要改变1和2节点的指向&#xff0c;我用h1表示节点1&#xff0c;我创建一个新的节点ans&#xff0c;先拿ans指向节点2&#xff08;ans.next h1.n…

超简单小白攻略:如何利用黑群晖虚拟机和内网穿透实现公网访问

文章目录 前言本教程解决的问题是&#xff1a;按照本教程方法操作后&#xff0c;达到的效果是前排提醒&#xff1a; 1. 搭建群晖虚拟机1.1 下载黑群晖文件vmvare虚拟机安装包1.2 安装VMware虚拟机&#xff1a;1.3 解压黑群晖虚拟机文件1.4 虚拟机初始化1.5 没有搜索到黑群晖的解…

聚合支付的特点与应用建议

随着互联网技术的发展和繁荣&#xff0c;支付行业的发展如火如荼。目前已进入移动支付时代&#xff0c;支付手段和方式不断更新。2017年&#xff0c;建行、工行推出二维码支付&#xff0c;开展综合支付收单业务。 聚合支付具有灵活、方便、低成本、近市场的特点&#xff0c;符合…

HarmonyOS应用开发者基础认证【满分答案】

HarmonyOS应用开发者基础认证 一、判断题二、单选题三、多选题 一、判断题 在Column和Row容器组件中&#xff0c;justifyContent用于设置子组件在主轴方向上的对齐格式&#xff0c;alignItems用于设置子组件在交叉轴方向上的对齐格式。&#xff08;正确&#xff09; 所有使用C…

vue2 .sync 修饰符

vue2 .sync 修饰符 **创建 工程&#xff1a; H:\java_work\java_springboot\vue_study ctrl按住不放 右键 悬着 powershell H:\java_work\java_springboot\js_study\Vue2_3入门到实战-配套资料\01-随堂代码素材\day04\准备代码\13-sync修饰符 vue --version vue create v-sy…

Ubuntu 16.04 LTS third maintenance update release

Ubuntu 16.04 LTS (Xenial Xerus)今天迎来的第三个维护版本更新中&#xff0c;已经基于Linux Kernel 4.10内核&#xff0c;而且Mesa图形栈已经升级至17.0版本。Adam Conrad表示&#xff1a;“像此前LTS系列相似&#xff0c;16.04.3对那些使用更新硬件的用户带来了硬件优化。该版…

ios设备管理软件iMazing 2.17.11官方中文版新增功能介绍

iMazing 2.17.11官方中文版(ios设备管理软件)是一款管理苹果设备的软件&#xff0c; Windows 平台上的一款帮助用户管理 IOS 手机的应用程序&#xff0c;软件功能非常强大&#xff0c;界面简洁明晰、操作方便快捷&#xff0c;设计得非常人性化。iMazing官方版与苹果设备连接后&…

Leetcode hot 100之动态规划【递推公式】

目录 入门理解 斐波那契(Fibonacci&#xff09;数列&#xff1a;递归 数塔&#xff1a;递推 递推公式 最小路径和 遍历顺序 整数拆分&#xff1a;拆分为和&#xff0c;乘积最大化 背包&#xff1a;&#xff1a; ->装包 框架 01背包&#xff1a;不可复选 倒序遍历 …

Ubuntu系统下配置安装区块链Hyperledger Fabric(新手小白篇)

有些安装过程比较简单的&#xff0c;不会详细赘述。主要还是集中在Hyperledger Fabric的配置上。 本篇主要介绍在Ubuntu系统上安装Hyperledger Fabric的过程。这里使用的Ubuntu&#xff1a;16.04 LTS。 1. Git安装 Git工具安装命令如下&#xff1a; sudo apt update sudo ap…

如何提高敏捷迭代效率?sprint backlog

​敏捷开发的核心就是小步快跑&#xff0c;快速迭代。过去&#xff0c;企业开发的需求是完整的、清晰的、固定的&#xff0c;产品定义也是稳定的&#xff0c;因此企业在项目开发中经常采用自上而下、相互衔接且固定次序的瀑布开发模式。而在当今&#xff0c;中国互联网快速发展…

Stm32_标准库_14_串口蓝牙模块_解决手机与蓝牙模块数据传输的不完整性

由手机向蓝牙模块传输时间信息&#xff0c;Stm32获取信息并将已存在信息修改为传入信息 测试代码&#xff1a; #include "stm32f10x.h" // Device header #include "Delay.h" #include "OLED.h" #include "Serial.h"uint16_t num…

计算机操作系统-第九天

1、虚拟机 传统计算机的特点&#xff1a;一台物理机器只能运行一个操作系统 虚拟机的特点&#xff1a; 使用虚拟化技术&#xff0c;将一台物理机器虚拟化为多台虚拟机器&#xff08;Virtual Machine&#xff0c;简称VM&#xff09;每个虚拟机都可以独立运行一个操作系统 虚拟…

生物标志物发现中的无偏数据分析策略

目录 0. 导论基本概念 1. 生物标志物发现的注意事项2. 数据预处理2.1 高质量原始数据和缺失值处理2.2 数据过滤2.3 数据归一化 3. 数据质量评估3.1 混杂因素3.2 类别分离3.3 功效分析3.4 批次效应 4. 生物标志物发现4.1 策略4.2 数据分析工具4.3 模型优化策略 0. 导论 组学技术…

CSS复习笔记

CSS 文章目录 CSS1.概念2.CSS 引入方式3.选择器基础选择器:标签选择器类选择器id 选择器通配符选择器 复合选择器:**后代选择器****子代选择器****并集选择器****交集选择器-了解****伪类选择器** 结构伪类选择器&#xff1a;**:nth-child&#xff08;公式&#xff09;**伪元素…