组播组可以是永久的也可以是临时的。组播组地址中,有一部分由官方分配的,称为永久组播组。永久组播组保持不变的是它的ip地址,组中的成员构成可以发生变化。永久组播组中成员的数量都可以是任意的,甚至可以为零。那些没有保留下来供永久组播组使用的ip组播地址,可以被临时组播组利用。
224.0.0.0~224.0.0.255 为预留的组播地址(永久组地址),地址224.0.0.0保留不做分配,其它地址供路由协议使用; 224.0.1.0~224.0.1.255 是公用组播地址,可以用于Internet;欲使用需申请。 224.0.2.0~238.255.255.255 为用户可用的组播地址(临时组地址),全网范围内有效; 239.0.0.0~239.255.255.255 为本地管理组播地址,仅在特定的本地范围内有效。
可使用ip ad命令查看网卡编号,如:
llycast$ ip ad
if_nametoindex 命令可以根据网卡名,获取网卡序号。
组播建立过程 组播结构图 代码/************************************************************************* > File Name: server.c > Author: 杨永利 > Mail: 1795018360@qq.com > Created Time: 2020年10月28日 星期三 18时31分47秒 ************************************************************************/ #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <string.h> #include <arpa/inet.h> #include <net/if.h> int main(int argc, char const *argv[]) { // 创建套接字 int fd = socket(AF_INET, SOCK_DGRAM, 0); if(fd == -1) { perror("socket error"); exit(1); } // 绑定server的iP和端口 struct sockaddr_in serv; memset(&serv, 0, sizeof(serv)); serv.sin_family = AF_INET; serv.sin_port = htons(8787); // server端口 serv.sin_addr.s_addr = htonl(INADDR_ANY); int ret = bind(fd, (struct sockaddr*)&serv, sizeof(serv)); if(ret == -1) { perror("bind error"); exit(1); } // 初始化客户端地址信息 struct sockaddr_in client; memset(&client, 0, sizeof(client)); client.sin_family = AF_INET; client.sin_port = htons(6767); // 客户端要绑定的端口 我懒了 // 给服务器开放组播权限 struct ip_mreqn flag; // 使用组播地址给客户端发数据 inet_pton(AF_INET, "239.0.0.10", &client.sin_addr.s_addr); inet_pton(AF_INET, "0.0.0.0", &flag.imr_address.s_addr); // 本地IP flag.imr_ifindex = if_nametoindex("ens33"); setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, &flag, sizeof(flag)); // 开始通信 while(1) { // 一直给客户端发数据 static int num = 0; char buf[1024] = {0}; sprintf(buf, "hello, udp == %d\n", num++); int ret = sendto(fd, buf, strlen(buf)+1, 0, (struct sockaddr*)&client, sizeof(client)); if(ret == -1) { perror("sendto error"); break; } printf("server == send buf: %s\n", buf); sleep(1); } close(fd); return 0; }
/************************************************************************* > File Name: client.c > Author: 杨永利 > Mail: 1795018360@qq.com > Created Time: 2020年10月28日 星期三 18时47分21秒 ************************************************************************/ #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <string.h> #include <arpa/inet.h> #include <net/if.h> int main(int argc, const char* argv[]) { int fd = socket(AF_INET, SOCK_DGRAM, 0); if(fd == -1) { perror("socket error"); exit(1); } // 绑定iP和端口 struct sockaddr_in client; memset(&client, 0, sizeof(client)); client.sin_family = AF_INET; client.sin_port = htons(6767); // ........ inet_pton(AF_INET, "0.0.0.0", &client.sin_addr.s_addr); int ret = bind(fd, (struct sockaddr*)&client, sizeof(client)); if(ret == -1) { perror("bind error"); exit(1); } // 加入到组播地址 struct ip_mreqn fl; inet_pton(AF_INET, "239.0.0.10", &fl.imr_multiaddr.s_addr); inet_pton(AF_INET, "0.0.0.0", &fl.imr_address.s_addr); fl.imr_ifindex = if_nametoindex("ens33"); setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &fl, sizeof(fl)); // 接收数据 while(1) { char buf[1024] = {0}; int len = recvfrom(fd, buf, sizeof(buf), 0, NULL, NULL); if(len == -1) { perror("recvfrom error"); break; } printf("client == recv buf: %s\n", buf); } close(fd); return 0; }