UDP多播

一、多播概念

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

只要加入了224.0.0.2多播组地址并且端口号为8081的客户端,服务器绑定的多播组224.0.0.2都会接收到客户端发来的数据。

  • 2
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Java 使用 MulticastSocket 类创建 UDP 多播套接字以接收发送到多播 IP 地址的数据报包。以下是一个接收 UDP 多播消息的 Java 代码示例: ``` import java.net.DatagramPacket; import java.net.InetAddress; import java.net.MulticastSocket; public class UDPMulticastReceiver { public static void main(String[] args) throws Exception { int mcPort = 12345; String mcIPStr = "230.1.1.1"; MulticastSocket mcSocket = null; InetAddress mcIPAddress = null; mcIPAddress = InetAddress.getByName(mcIPStr); mcSocket = new MulticastSocket(mcPort); System.out.println("Multicast Receiver running at:" + mcSocket.getLocalSocketAddress()); mcSocket.joinGroup(mcIPAddress); DatagramPacket packet = new DatagramPacket(new byte[1024], 1024); System.out.println("Waiting for a multicast message..."); mcSocket.receive(packet); String msg = new String(packet.getData(), packet.getOffset(), packet.getLength()); System.out.println("[Multicast Receiver] Received:" + msg); mcSocket.leaveGroup(mcIPAddress); mcSocket.close(); } } ``` 以下是一个发送 UDP 多播消息的 Java 代码示例: ``` import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; public class UDPMulticastSender { public static void main(String[] args) throws Exception { int mcPort = 12345; String mcIPStr = "230.1.1.1"; DatagramSocket udpSocket = new DatagramSocket(); InetAddress mcIPAddress = InetAddress.getByName(mcIPStr); byte[] msg = "Hello".getBytes(); DatagramPacket packet = new DatagramPacket(msg, msg.length); packet.setAddress(mcIPAddress); packet.setPort(mcPort); udpSocket.send(packet); System.out.println("Sent a multicast message."); System.out.println("Exiting application"); udpSocket.close(); } } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值