一、多播概念
1.1、多播
多播又称为:组播。 一个人发数据,只有加入到多播组的人接收数据
1.2、多播的特点
1、多播地址标示一组接口
2、多播可以用于广域网使用
3、在IPv4中,多播是可选的
1.3、多播地址
IPv4的D类地址是多播地址
十进制:224.0.0.1~239.255.255.254
十六进制:E0.00.00.01~EF.FF.FF.FE
组播地址是分类编址的IPv4地址中的D类地址,又叫多播地址,他的前四位必须是1110,多播组的地址是D类IP,规定是224.0.0.0——239.255.255.255。
1.4、多播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为本地管理组播地址,仅在特定的本地范围内有效
1.5、多播地址向以太网MAC地址的映射
1.5.1、计算多播mac地址(mac地址占48位)
解题方法:组播地址MAC以01-00-5e开头(规定的),占25bit。由于MAC地址是48bit,而IP地址有32bit,因此需要从ip地址获取后23位。如何获取,最安全的又准确的方法:就是把IP地址,换成二进制数。第2个8位中的第1位规定为0,去掉前8位,再把剩下的二进制换成16进制,最后添加在01-00-5e后面即可
举例说明
例如 1、求224.128.129.130的组播MAC过程如下:
第一步:我们可以永远都知道多播mac地址前25位,都是01-00-5e(规定的)。
第二步:把ip地址化为二进制
224.128.129.130的二进制形式
1110 0000 1000 0000 1000 0001 1000 0010 把第2个8位中的第1位规定为0,即红色的1改为0
得: 1110 0000 0000 0000 1000 0001 1000 0010 把前8位去掉,即黑色部分去掉
得: 0000 0000 1000 0001 1000 0010
第三步:把得出的二进制转化成16进制(0000 0000 1000 0001 1000 0010 )
得: 00-81-82
第三步:合并
该ip的组播mac地址:01-00-5e-00-81-82
二、多播工作过程
多播不需要设置setsockopt(套接字选项)
比起广播,多播具有可控性,只有加入多播组的接收者才可以接收数据,否则接收不到
2.1、分析发送端设置流程
第一步:创建套接字——socket函数
第二步:设置为UDP协议和端口号(此端口为 对方的端口号 )
第三步:设置IPV4,由于使用的是多播,需要把ip地址 设为多播地址.
多播地址范围:224.0.0.0——239.255.255.255。
第四步:设置传输为以太网,mac地址根据ip地址 (转看1.5示例)
2.2、分析如何传输与接收
第一步:把打包好数据包,发送到多播组里。
第二步:接收者想要接收到信息,必须要先加入多播组里
三、多播代码流程
发送者:
第一步:创建套接字 socket()
第二步:向多播地址发送数据 sendto()
接收者:
第一步:创建套接字 socket()
第二步:设置为加入多播组 setsockopt()第三步:将套接字与多播信息结构体绑定 bind()
第五步:接收数据
四、多播地址结构
在IPv4因特网域(AF_INET)中,多播地址结构体用如下结构体ip_mreq表示
五、多播套接口选项(接收者需要使用此函数加入多播组)
头文件
#include <sys/socket.h>
函数:int setsockopt(int socket, int level, int option_name,const void *option_value, socklen_t option_len);
功能:设置一个套接字的选项(属性)
参数:
socket:文件描述符
level:协议层次
IPPROTO_IP IP层次
option_name:选项的名称
IP_ADD_MEMBERSHIP 加入多播组
option_value:设置的选项的值结构体
struct ip_mreq
{
struct in_addr imr_multiaddr; //组播ip地址
struct in_addr imr_interface; //主机地址
INADDR_ANY 任意主机地址(自动获取你的主机地址)
};
option_len:option_value的长度
返回值:
成功:0
失败:‐1
多播设置
mreq.imr_multiaddr.s_addr=inet_addr(argv[1]);
mreq.imr_interface.s_addr=INADDR_ANY;// INADDR_ANY获取自己的ip地址
socklen_t optlen =sizeof(mreq);
if(setsockopt(sockfd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,optlen) < 0)
{
perror("fail to setsockopt");
exit(1);
}
5.1、发送者(代码)
#include<stdio.h>
#include<stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main(int argc ,char *argv[])
{
if(argc<3)
{
printf("error lose ip port\n");
exit(1);
}
int sockfd;
if((sockfd=socket(AF_INET,SOCK_DGRAM,0))==-1)
{
perror("fail to sockfd");
exit(1);
}
struct sockaddr_in mysockaddr;
mysockaddr.sin_family = AF_INET;
mysockaddr.sin_port =htons(atoi(argv[2]));
mysockaddr.sin_addr.s_addr=inet_addr(argv[1]);
socklen_t addrlen= sizeof(mysockaddr);
char buf[128];
while(1)
{
fgets(buf,sizeof(buf),stdin);
if(sendto(sockfd,buf,sizeof(buf),0,(struct sockaddr *)&mysockaddr,addrlen)==-1)
{
perror("fail to sendto");
exit(1);
}
}
close(sockfd);
return 0;
}
5.2、接收者(代码)
#include<stdio.h>
#include<stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include<string.h>
int main(int argc ,char *argv[])
{
if(argc<3)
{
printf("input fail lose ip port");
exit(1);
}
int sockfd;
if((sockfd=socket(AF_INET,SOCK_DGRAM,0))==-1)
{
perror("fail to sockfd");
exit(1);
}
struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr=inet_addr(argv[1]);
mreq.imr_interface.s_addr=INADDR_ANY;
socklen_t optlen =sizeof(mreq);
if(setsockopt(sockfd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,optlen) < 0)
{
perror("fail to setsockopt");
exit(1);
}
struct sockaddr_in mysockaddr;
mysockaddr.sin_family = AF_INET;
mysockaddr.sin_port =htons(atoi(argv[2]));
mysockaddr.sin_addr.s_addr=inet_addr(argv[1]);
socklen_t addrlen= sizeof(mysockaddr);
if(bind(sockfd,(struct sockaddr *)&mysockaddr,addrlen)==-1)
{
perror("fail to bind");
exit(1);
}
char buf[128];
struct sockaddr_in sendsockaddr;
socklen_t sendaddrlen=sizeof(sendsockaddr);
while(1)
{
if(recvfrom(sockfd,buf,sizeof(buf),0,(struct sockaddr *)&sendsockaddr,&sendaddrlen)==-1)
{
perror("fail to recvfrom");
exit(1);
}
printf("[%s ‐ %d]: %s\n", inet_ntoa(sendsockaddr.sin_addr), ntohs(sendsockaddr.sin_port),buf);
}
close(sockfd);
return 0;
}
运行结果
多播地址范围:224.0.0.0——239.255.255.255。
我设置了多播组地址为:224.0.0.2 端口号为8081文章来源:https://www.toymoban.com/news/detail-459584.html
只要加入了224.0.0.2多播组地址并且端口号为8081的客户端,服务器绑定的多播组224.0.0.2都会接收到客户端发来的数据。文章来源地址https://www.toymoban.com/news/detail-459584.html
到了这里,关于UDP多播的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!