医疗网站建设市场,苏州关键词优化怎样,go网站做富集分析,网站功能价格表UDP特性之组播 1. 组播的特点2. 设置主播属性2.1 发送端2.2 接收端 3. 组播通信流程3.1 发送端3.2 接收端 4. 通信代码 原文链接
在公司测试广播和多播有一点问题。。。
1. 组播的特点
组播也可以称之为多播这也是UDP的特性之一。组播是主机间一对多的通讯模式#xff0c;是… UDP特性之组播 1. 组播的特点2. 设置主播属性2.1 发送端2.2 接收端 3. 组播通信流程3.1 发送端3.2 接收端 4. 通信代码 原文链接
在公司测试广播和多播有一点问题。。。
1. 组播的特点
组播也可以称之为多播这也是UDP的特性之一。组播是主机间一对多的通讯模式是一种允许一个或多个组播源发送同一报文到多个接收者的技术。组播源将一份报文发送到特定的组播地址组播地址不同于单播地址它并不属于特定某个主机而是属于一组主机。一个组播地址表示一个群组需要接收组播报文的接收者都加入这个群组。
广播只能在局域网访问内使用组播既可以在局域网中使用也可以用于广域网在发送广播消息的时候连接到局域网的客户端不管想不想都会接收到广播数据组播可以控制发送端的消息能够被哪些接收端接收更灵活和人性化。广播使用的是广播地址组播需要使用组播地址。广播和组播属性默认都是关闭的如果使用需要通过setsockopt()函数进行设置。
组播需要使用组播地址在 IPv4 中它的范围从 224.0.0.0 到 239.255.255.255并被划分为局部链接多播地址、预留多播地址和管理权限多播地址三类: 组播地址不属于任何服务器或个人它有点类似一个微信群号任何成员组播源往微信群组播IP发送消息组播数据这个群里的成员组播接收者都会接收到此消息。
2. 设置主播属性
如果使用组播进行数据的传输不管是消息发送端还是接收端都需要进行相关的属性设置设置函数使用的是同一个即setsockopt()。
2.1 发送端
发送组播消息的一端需要设置组播属性具体的设置方式如下
int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);参数: sockfd用于UDP通信的套接字 level套接字级别设置组播属性需要将该参数指定为IPPTOTO_IP optname: 套接字选项名设置组播属性需要将该参数指定为IP_MULTICAST_IF optval设置组播属性这个指针需要指向一个struct in_addr{} 类型的结构体地址这个结构体地址用于存储组播地址并且组播IP地址的存储方式是大端的。 optlenoptval指针指向的内存大小即sizeof(struct in_addr)
struct in_addr
{in_addr_t s_addr; // unsigned int
}; 返回值函数调用成功返回0调用失败返回-1
2.2 接收端
因为一个组播地址表示一个群组所以需要接收组播报文的接收者都加入这个群组和想要接收群消息就必须要先入群是一个道理。加入到这个组播群组的方式如下
int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);参数: sockfd基于udp的通信的套接字 level套接字级别加入到多播组该参数需要指定为IPPTOTO_IP optname套接字选项名加入到多播组该参数需要指定为IP_ADD_MEMBERSHIP optval加入到多播组这个指针应该指向一个struct ip_mreqn{}类型的结构体地址 optlenoptval指向的内存大小即sizeof(struct ip_mreqn)
typedef unsigned int uint32_t;
typedef uint32_t in_addr_t;
struct sockaddr_in addr;struct in_addr
{in_addr_t s_addr; // unsigned int
};struct ip_mreqn
{struct in_addr imr_multiaddr; // 组播地址/多播地址struct in_addr imr_address; // 本地地址int imr_ifindex; // 网卡的编号, 每个网卡都有一个编号
};
// 必须通过网卡名字才能得到网卡的编号: 可以通过 ifconfig 命令查看网卡名字
#include net/if.h
// 将网卡名转换为网卡的编号, 参数是网卡的名字, 比如: ens33
// 返回值就是网卡的编号
unsigned int if_nametoindex(const char *ifname);3. 组播通信流程
发送组播消息的一端需要将数据发送到组播地址和固定的端口上想要接收组播消息的终端需要绑定对应的固定端口然后加入到组播的群组最终就可以实现数据的共享。 3.1 发送端
创建通信的套接字
// 第二个参数是 SOCK_DGRAM, 第三个参数0表示使用报式协议中的udp
int fd socket(AF_INET, SOCK_DGRAM, 0);主动发送数据的一端不需要手动绑定端口自动随机分配就可以了设置UDP组播属性
// 设置组播属性
struct in_addr opt;
// 将组播地址初始化到这个结构体成员中
inet_pton(AF_INET, 239.0.1.10, opt.s_addr);
setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, opt, sizeof(opt));使用组播地址发送组播消息到固定的端口接收端需要绑定这个端口
sendto();关闭套接字文件描述符
close(fd);3.2 接收端
创建通信的套接字
// 第二个参数是 SOCK_DGRAM, 第三个参数0表示使用报式协议中的udp
int fd socket(AF_INET, SOCK_DGRAM, 0);绑定固定的端口发送端应该将数据发送到接收端绑定的端口上
bind();加入到组播的群组中入群之后就可以接受组播消息了。
// 加入到多播组
struct ip_mreqn opt;
// 要加入到哪个多播组, 通过组播地址来区分
inet_pton(AF_INET, 239.0.1.10, opt.imr_multiaddr.s_addr);
opt.imr_address.s_addr INADDR_ANY;
opt.imr_ifindex if_nametoindex(ens33);
setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, opt, sizeof(opt));接收组播数据
recvfrom();关闭套接字文件描述符
close(fd);4. 通信代码
发送端
#include stdio.h
#include stdlib.h
#include unistd.h
#include string.h
#include arpa/inet.hint main()
{// 1. 创建通信的套接字int fd socket(AF_INET, SOCK_DGRAM, 0);if(fd -1){perror(socket);exit(0);}// 2. 设置组播属性struct in_addr opt;// 将组播地址初始化到这个结构体成员中即可inet_pton(AF_INET, 239.0.1.10, opt.s_addr);setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, opt, sizeof(opt));char buf[1024];struct sockaddr_in cliaddr;int len sizeof(cliaddr);cliaddr.sin_family AF_INET;cliaddr.sin_port htons(9999); // 接收端需要绑定9999端口// 发送组播消息, 需要使用组播地址, 和设置组播属性使用的组播地址一致就可以inet_pton(AF_INET, 239.0.1.10, cliaddr.sin_addr.s_addr);// 3. 通信int num 0;while(1){sprintf(buf, hello, client...%d\n, num);// 数据广播sendto(fd, buf, strlen(buf)1, 0, (struct sockaddr*)cliaddr, len);printf(发送的组播的数据: %s\n, buf);sleep(1);}close(fd);return 0;
}
注意事项在组播数据的发送端需要先设置组播属性发送的数据是通过sendto()函数发送到某一个组播地址上并且在程序中数据发送到了接收端的9999端口因此接收端程序必须要绑定这个端口才能收到组播消息。
接收端
#include stdio.h
#include stdlib.h
#include unistd.h
#include string.h
#include arpa/inet.h
#include net/if.hint main()
{// 1. 创建通信的套接字int fd socket(AF_INET, SOCK_DGRAM, 0);if(fd -1){perror(socket);exit(0);}// 2. 通信的套接字和本地的IP与端口绑定struct sockaddr_in addr;addr.sin_family AF_INET;addr.sin_port htons(9999); // 大端addr.sin_addr.s_addr INADDR_ANY; // 0.0.0.0int ret bind(fd, (struct sockaddr*)addr, sizeof(addr));if(ret -1){perror(bind);exit(0);}// 3. 加入到多播组struct ip_mreqn opt;// 要加入到哪个多播组, 通过组播地址来区分inet_pton(AF_INET, 239.0.1.10, opt.imr_multiaddr.s_addr);opt.imr_address.s_addr INADDR_ANY;opt.imr_ifindex if_nametoindex(ens33); // enp0s3setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, opt, sizeof(opt));char buf[1024];// 3. 通信while(1){// 接收广播消息memset(buf, 0, sizeof(buf));// 阻塞等待数据达到recvfrom(fd, buf, sizeof(buf), 0, NULL, NULL);printf(接收到的组播消息: %s\n, buf);}close(fd);return 0;
}注意事项作为组播消息的接收端必须要先绑定一个固定端口发送端就可以把数据发送到这个固定的端口上了然后加入到组播的群组中一个组播地址可以看做是一个群组这样就可以接收到组播消息了。