赞
踩
UDP广播是一种网络通信的方式,在广域网或局域网中,UDP广播可以向多个目标主机发送数据包,使得网络中的所有设备都能接收到广播消息。一定是采用UDP协议。
1、面向无连接:UDP广播不需要建立连接,可以直接发送数据包到目标设备。
2、广播特性:UDP广播可以向一个网络中的所有设备发送数据包。
3、不可靠性:UDP广播发送的数据包无法保证传输的可靠性,可能会发生数据丢失、错误等情况。
4、速度快、开销小:UDP广播不需要建立连接,因此传输速度快,开销小,适用于实时流媒体传输等应用场景。
5、 安全性较低:UDP广播发送的数据包可以被网络中的其他设备接收,可能会存在数据泄露的风险。
6、适用于广播通信场景:UDP广播适用于需要向网络中所有设备发送数据的场景,比如寻找可用设备、传输实时视频或音频数据等。
UDP广播主要用于数据的实时传输和设备的发现,常见的应用场景包括:
1、视频和音频的实时传输:UDP广播可以使得多个设备同时接收到同一流的数据,实现实时的视频会议和音频播放等功能。
2、网络打印机的自动发现:通过UDP广播,打印机可以向网络中广播自己的存在,从而被所有的设备发现和使用。
3、多人游戏的联机:UDP广播可以将游戏数据同时发送给所有玩家的设备,实现多人游戏的联机功能。
4、网络摄像头的实时监控:通过UDP广播,摄像头可以将实时的视频流发送给所有监控软件,使得监控人员能够同时查看视频。
(1)、建立套接字。使用socket()
(2)、设置套接字属性为广播。使用setsockopt()
(3)、绑定自己的IP地址和端口号。使用bind()(可以省略)
(4)、发送数据,并指定接收方为广播地址。使用sendto()
(5)、关闭套接字
(1)、建立套接字。使用socket()
(2)、设置端口复用。使用setsockopt()(可选,推荐)
(3)、绑定IP地址为广播地址和端口号。使用bind()(不可以省略)
(4)、接收数据。使用recvfrom()
(5)、关闭套接字
- // 建立套接字
- 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
- // 设置端口的状态
- 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)

- // 绑定自己的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地址需要调用专门的函数转换成网络字节序

- // 第一组接口
- // 主机转网络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); // 常用

- // 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)

- // 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)

- // 关闭套接字
- int close(int fd);
-
- // 接口说明
- 返回值:成功返回0,失败返回-1
- 参数fd:套接字文件描述符
实现UDP广播的演示
- // 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}; // 数据缓冲区
-
- // 注意输入广播地址,格式为*.*.*.255
- printf("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;
- }

- // 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)); // 先清空IP
- strcpy(ip, inet_ntoa(send_addr.sin_addr)); // 网络IP转主机IP
- port = 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广播主要用于数据的实时传输和设备的发现。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。