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.mzph.cn/news/109285.shtml

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

相关文章

Django ORM查询

Django提供了一套非常方便的类似SqlAlchemy ORM的通过对象调用的方式操作数据库表的ORM框架。 Django ORM操作主要分为以下几类&#xff1a; 增&#xff1a;向表内插入一条数据删&#xff1a;删除表内数据&#xff08;物理删除&#xff09;改&#xff1a;update操作更新某条数…

数字化 | 智能电子日历

想要一款随时随地都能掌握日期的电子日历吗&#xff1f; WiFi通信&#xff0c;实时更新&#xff0c;超低功耗&#xff0c;可充电&#xff0c;超长续航&#xff0c;电子纸&#xff0c;黑白红三色显示的电子日历&#xff0c;就是你的最佳选择&#xff01; 无论是在办公室、家中或…

QCC51XX-QCC30XX系列开发教程(实战篇) 之 12.4-空间音频手机侧和耳机侧接口设计时序图

查看全部教程开发请点击:全网最全-QCC51xx-QCC30xx(TWS)系列从入门到精通开发教程汇总(持续更新中) ==================================================================== 版权归作者所有,未经允许,请勿转载。 ==========================================

自建应用-企业微信-侧边栏开发配置

企业微信侧边栏开发配置 配置侧边栏配置后效果图js-sdk 配置侧边栏 配置后效果图 js-sdk https://developer.work.weixin.qq.com/document/path/91789

“系统重要性银行”光环下,南京银行的重重忧思

撰稿|行星 来源|贝多财经 南京银行喜忧参半&#xff0c;提名系统重要性银行&#xff0c;还面临信誉老题、业绩新题难解的问题。 近期&#xff0c;中国人民银行、国家金融监督管理总局开展了2023年度我国系统重要性银行评估&#xff0c;认定20家国内系统重要性银行&#xff0…

如何分析K8S中的OOMKilled问题(Exit Code 137)

什么是 OOMKilled Kubernetes 错误&#xff08;Exit Code 137&#xff09; 当 Kubernetes 集群中的容器超过其内存限制时&#xff0c;Kubernetes 系统可能会终止该容器并显示“OOMKilled”错误&#xff0c;这表明该进程由于内存不足而被终止。此错误的退出代码是 137。 如果遇…

代码随想录算法训练营第二十五天丨 回溯算法part03

39. 组合总和 思路 题目中的无限制重复被选取&#xff0c;提示&#xff1a;1 < candidates[i] < 200。 本题和77.组合 (opens new window)&#xff0c;216.组合总和III (opens new window)的区别是&#xff1a;本题没有数量要求&#xff0c;可以无限重复&#xff0c;但…

记录:移动设备软件开发(layout六大布局)

目录 前言layoutLinearLayout线性布局LinearLayout的常用属性Android&#xff1a;orientation属性Android&#xff1a;gravity属性 TableLayout表格布局TableLayout的常用属性collapsecolumns属性shrinkcolums属性stretchcoumns属性 RelativeLayout相对布局Absolute Layout绝对…

构造shiro poc

攻击shiro思路 伪造加密过程 shiro在容器初始化的时候会实例化CookieRememberMeManager对象&#xff0c;并且设置加密解密方式 实例化时调用父类构造方法&#xff0c;设置加密方式为AES&#xff0c;并且设置key 看下调用栈 <init>:109, AbstractRememberMeManager (org…

12JVM基础

五、JVM 17、JVM基础 说一下堆栈的区别&#xff1f; 功能方面&#xff1a;堆是用来存放对象的&#xff0c;栈是用来执行程序的。 共享性&#xff1a;堆是线程共享的&#xff0c;栈是线程私有的。 空间大小&#xff1a;堆大小远远大于栈。队列和栈是什么&#xff1f;有什么区别…

python数据挖掘从入门到实战

欢迎关注博主 Mindtechnist 或加入【智能科技社区】一起学习和分享Linux、C、C、Python、Matlab&#xff0c;机器人运动控制、多机器人协作&#xff0c;智能优化算法&#xff0c;滤波估计、多传感器信息融合&#xff0c;机器学习&#xff0c;人工智能等相关领域的知识和技术。关…

typeScript 类型什么时候使用any?

在类型不确定的情况下&#xff0c;使用 any 是一种选项&#xff0c;但通常不是最佳选择。使用 any 类型会让你失去 TypeScript 提供的类型安全性和编译时检查。以下是几种处理类型不确定性的更好方法&#xff1a; 联合类型&#xff08;Union Types&#xff09;: 如果一个值可能…

电商独立站小程序开发方案

随着移动互联网的迅速发展&#xff0c;电商行业也逐渐向小程序平台转移。开发一款电商小程序对于拓展销售渠道、提高用户体验、增加用户忠诚度等方面都有着重要的意义。本文将围绕电商小程序的开发背景、需求分析、技术选型、开发流程、风险控制、商业模式和市场前景等方面进行…

python代码调用文件或数据库中保存的脚本

这里采用的读取excel 1、先写一个测试方法 def demo5():import xlrdimport randomwb xlrd.open_workbook("code.xls")st wb.sheet_by_index(0)code st.cell_value(0, 0)list ["6666", asd, 1ad23, 1f23, 12g3, 1b3, 12r3]code2 st.cell_value(0, 1)…

[游戏开发][Unity] UnityWebRequest中断续传

UnityWebRequest和WWW加载的底层原理还是Http 断点续传的原理 UnityWebRequest第一次请求Url&#xff0c;如果请求成功&#xff0c;从头文件里把文件总长度读出来 long totalLength long.Parse(huwr.GetResponseHeader("Content-Length")) 由于文件是边下边写入的&a…

JVS规则引擎及智能BI又更新新功能啦!赶紧来试试

规则引擎更新功能 新增: 1.复合变量新增排序、排名功能 可以按照特定的顺序对数据进行排列&#xff0c;确定规则的优先级&#xff0c;可以提高数据处理效率&#xff0c;帮助分析人员更好地了解数据分布和趋势。 2.决策流新增动态日志功能 动态日志可以记录规则执行的过程和…

Jmeter性能测试(压力测试)

1.先保存 2.添加请求&#xff08;即添加一个线程组&#xff09; 3.添加取样器&#xff08;在线程组下面添加一个http请求&#xff09; 场景1&#xff1a;模拟半小时之内1000个用户访问服务器资源&#xff0c;要求平均响应时间在3000毫秒内&#xff0c;且错误率为0&#xff0…

【Linux初阶】多线程4 | POSIX信号量,基于环形队列的生产消费模型,线程池,线程安全的单例模式,STL-智能指针和线程安全

文章目录 ☀️一、POSIX信号量&#x1f33b;1.引入&#x1f33b;2.信号量的概念&#x1f33b;3.信号量函数 ☀️二、基于环形队列的生产消费模型&#x1f33b;1.理解环形队列&#x1f33b;2.代码案例 ☀️三、线程池☀️四、线程安全的单例模式&#x1f33b;1.单例模式与设计模…

如何系统性的学习报关知识

学习报关知识的方法如下&#xff1a; 学习法律法规&#xff1a;报关是受国家法律法规约束的&#xff0c;因此学习法律法规是非常重要的。可以去中华人民共和国海关总署官网查询相关法规。 学习关税分类&#xff1a;了解不同商品的分类和税率&#xff0c;可以去海关总署官网查询…

共享盘文件如何防止别人恶意删除

在如今数字化信息交流的社会中&#xff0c;共享文件已经成为很常见的设置了。然而&#xff0c;对于共享盘文件而言&#xff0c;恶意删除是一种常见的安全威胁&#xff0c;因此用户需要掌握一些方法来保护自己的文件安全。本文将介绍防止别人恶意删除共享盘文件的方法&#xff0…