java的IP组播

news2024/11/27 2:44:40

文章目录

  • 1. 简介
  • 2. 组播地址和组
  • 3. 客户端和服务器
  • 4. 路由器和路由
  • 5. 使用组播Socket
  • 6. 构造函数
  • 7. 与组播组通信
  • 8. 案例实战

1. 简介

前面介绍的Socket都是单播Socket,它们提供点对点的通信。单播Socket在两个明确的端点之间创建一个连接,有一个发送方和一个接收方。尽管点对点的通信有很多用途,但不是非常重要,很多任务则需要另外的一种不同的通信模型——组播。组播是通过TCP或UDP的附加协议实现的。Internet组播建立在UDP端口之上,Java中的组播使用UDP中介绍的DatagramPacket,以及一个新的MulticastSocket类

以下是组播的基本流程:

  • 创建组播组: 首先,需要创建一个组播组,它由一个组播地址表示。这个地址是在特定的IPv4或IPv6地址范围内选定的。
  • 加入组播组: 接收者需要向他们的本地路由器表明他们想要加入一个特定的组播组。这个过程通常使用Internet Group Management Protocol (IGMP) 或者在IPv6环境中的Multicast Listener Discovery (MLD) 协议。
  • 发送数据: 发送者向组播地址发送数据。这个过程并不需要知道谁是组的成员,只需要向组播地址发送数据即可。
  • 路由器处理: 当路由器接收到组播数据时,它需要将数据复制并发送给所有请求接收这个组播组数据的网络接口。路由器使用特定的组播路由协议,如Protocol Independent Multicast (PIM) 或Distance Vector Multicast Routing Protocol (DVMRP) 等,来决定如何最有效地将数据路由到其他路由器。
  • 接收数据: 最后,接收者从他们的本地路由器接收到组播数据。

组播比单播的点对点通信宽,但比广播通信窄而且目标更加明确。组播将数据从一个主机发送到多个不同的主机,但只发加入某个特定组播组的主机。(主机申请加入某个组播组,加入后也可以自愿离开,可订阅有点像),组播设计为尽可能无缝地用于Internet,大多数工作都由路由器完成,对于应用程序员是透明的。应用程序只是将数据报包发送给一个组播的地址,它在功能上与任何其他的IP地址没有什么区别,路由器将确保被分发到该组播组中的所有主机。需要注意数据报中称为TTL的首部字段。TTL是允许数据报经过的最大路由器跳数,当达到这个最大值时,即如果数据包已经经过这么多路由器,就会丢弃这个包。组播使用TTL作为一种专用的方法来限制包可以传输多远。

2. 组播地址和组

组播地址是称为组播组的一组主机共享地址。IPv4组播地址是CIDR组224.0.0.0/4中的IP地址。与所有的IP地址类似,组播地址可以有一个主机名。例如,组播地址224.0.1.1(网络时间协议分布式服务地址)就分配有主机名ntp.mcast.net。组播组是一组共享一个组播地址的Internet主机,任何发送给该组比地址的数据都会中继给组中的所有成员,主机可以在任何时候进入或离开组。组可以是永久的也可以是临时的。永久的组播组分配的地址不变,而不讨论组内的成员。大多数组播组都是临时的,只是在有成员时才存在。要创建一个新的组播组,所要做的就是在255.0.0.0到238.255.255.255间随机选择一个地址,为该地址构造一个InetAddress对象,开始向它发送数据。

3. 客户端和服务器

当一台主机希望向组播组发送数据时,它会将数据放在组播数据报中,组播数据报也就是发送到组播组的UDP数据报而已。组播数据通过UDP发送,虽然不可靠,但比通过面向连接到的TCP发送的数据要快上3倍。如果你要开发不能容忍数据丢失的组播应用程序,就要由你负责确定数据在传输中是否损害以及如何处理丢失的数据。一旦数据填充到一个或多个数据报,发送主机就把数据报发送到Internet,这就像发送正常(单播)UDP数据一样。发送主机首先向本地网络发送一个组播数据报,这个包立即到达相同子网中组播组的所有成员,如果这个包的TTL大于1,本地网络的组播路由器会把这个包转发到包含目标组成员的其他网络。当包到达一个最终目的地时,该外部网络的组播路由器会将这个包传输到作为组播成员的每个主机,如果必要,组播路由器还会将包重新传输到位于当前路由器和所有最终目的地之间路径上的下一个路由器。当数据到达组播组的一个主机时,该主机就像接收任何其他UDP数据报一样接收该数据,尽管包的目标地址和接收主机的地址不一致,主机之所有能识别数据包是发送给它的,这是因为它属于数据报所发往的组播组,接收主机必须监听正确的端口,准备在数据报到到达时进行处理。

4. 路由器和路由

下图展示了一个最简单的组播配置,一个服务器向四台连接同一个路由器的客户端发送相同的数据。组播Socket通过Internet向客户端的路由器发送一个数据流,这个路由器复制数据流,并发送到每个客户端。如果没有组播Socket,服务器就必须发出4个单独的数据流,并发送到每个客户端,大大降低了主干网的带宽。当然,实际的路由可能更加复杂,设计多层冗余路由器。不过,组播Socket的目标很简单:不管网络有多复杂,在任何指定的网段上,相同的数据绝不应发送多层。作为java,只需要创建一个MulfticastSocket,让这个Socket加入组播组,并在发送的DatagramPacket填充该组播组的地址即可,路由器和MulticastSocket类会处理其余的所有工作。
在这里插入图片描述
组播最大的限制在于是否有特殊的组播路由器(mrouter)。mrouter时重新配置的Internet路由器或工作站,支持IP组播扩展。为收发本地子网外的组播数据,你需要一个组播路由器。询问你的网络管理员,查看你的路由器是否支持组播。也可以尝试ping all-routers.mcast.net,如果有路由器回应说明你的网络连接着一个组播路由器。

在这里插入图片描述
但要让你的包到达任何指定的主机,你的主机和远程主机必须有一个由组播路由器构造的路径。或者有些网站可能连接着特殊的组播隧道软件,可以通过所有的路由器都理解的单播UDP传输组播数据。

5. 使用组播Socket

下面使用java.net.MulticastSocket类来组播数据

public class MulticastSocket extends DatagramSocket implements Closeable ,AutoCloseable

该类继承了DatagramSocket类,所以两者十分类似:将数据放在DatagramPacket中,然后通过MulticastSocket收发DatagramPacket对象。要接受远程完整的组播的数据,使用MulticstSocket()构造函数创建一个MulticastSocket对象。

//监听端口2300
MulticastSocket ms=new MulticastSocekt(2300);

接下来,使用MulticastSocket的joinGroup方法加入到一个组播组

InetAddress group=InetAddress.getByname("224.2.2.2");
ms.joinGroup(group);

这会通知你与服务器路径上的路由器开始发送数据,并告诉本地主机要将你的IP包发往组播组。一旦加入到组播组,就可以接受UDP数据了

byte[] buffer=new byte[8192];
DatagramPacket dp= new DatagramPacket(buffer, buffer.length);
ms.receive()

不再希望接收数据时,可以通过leaveGroup()方法离开组播组。然后调用close方法关闭Socket。向组播地址发送数据与向单播地址发送UDP数据很类似,不需要加入组播组就可以向组播地址发送数据。可以创建一个新的DatagramPacket,在包中填充数据和组播组的地址,将这个包发入send()方法

InetAddress ia= InetAddress.getByname("experiment.mcast,net");
byte[] data= "iasdfjadsjf slakdf".getBytes("UTF-8");
DatagramPacket dp= new DatagramPacket(data,data.length,ia, port);
MyulticastSokcet ms= new MulticastSocket();
ms.send(dp);

6. 构造函数

构造函数很简单,选择监听的端口就可以了,或者让系统给你分配一个匿名端口

public MulticastSocket() throws SocketException
public MulticastSocket(int port) throws SocketException
public MulticastSocket(SocketAddress bindAddress) throws SocketException

可以向构造函数传入一个null来创建一个未绑定的Socket,之后再用bind()方法进行连接。有些Socket选项只能子啊绑定之前设置,所以这个构造函数在这种情况下很有用。

InetAddress和SocketAddress都是Java网络编程中用于处理网络地址的类,但它们在使用方式和功能上有些不同。

  • InetAddress:这个类代表了互联网协议(IP)地址。一个InetAddress实例包含了一个IP地址的主机名和字面值。它不包含端口信息。所以,如果你要指定一个网络上的特定端点(即IP地址和端口号),你不能仅仅使用InetAddress。
  • SocketAddress:这是一个抽象类,用于表示套接字地址(即组合了IP地址和端口号的网络端点)。在Java网络编程中,SocketAddress的一个常见子类是InetSocketAddress。一个InetSocketAddress实例包含了一个InetAddress和一个端口号。

总的来说,你可以认为InetAddress是一个IP地址,而SocketAddress(更确切地说,InetSocketAddress)是一个完整的网络端点地址(即包括IP地址和端口号)。如果你在编程时需要同时处理IP地址和端口号,那么你可能需要使用InetSocketAddress。如果你只需要处理IP地址,那么你可能只需要InetAddress。

7. 与组播组通信

一旦创建MulticastSocket,可以完成下面4种关键操作

  • 加入组播组
  • 向组中成员发送数据
  • 接受组中的数据
  • 离开组播组

MulticastSocket类为操作1和4提供了方法。发送和接受使用send和receive方法即可。可以以任何顺序完成这些操作,不过必须在加入组后才能从组中接受数据。向组中发送数据并不需要先加入组。

 加入组

要加入一个组调用InetAddress或SocketAddress对象传递给joinGroup()方法:

public void joinGroup(InetAddress address) throws IOException
public void joinGroup(SocketAddress addrss, NetworkInterface interface)

接受数据就用UDP文章中介绍的方法即可。一个MulticastSocket对象可以加入多个组播组,组播组中的成员信息会被记录在组播路由器中,而不是对象中。在这里,你要使用存储在入站数据报中的地址来确定包要发往什么地址。NetworkInterface interface允许只加入指定本地网络上的组播组,例如下面代码尝试加入名为“eth0”的网络接口上IP地址为224.2.2.2的组。

MulticastSocket ms= new MulticastSocket();
SocketAddress group= new InetSocketAddress("224.2.2.2",40);
NetworkInterface ni= NetworkInterface.getByname("eth0");
if(ni!= null){
//来让多播套接字加入到指定的多播组,并指定使用特定的网络接口
	ms.joinGroup(group,ni);
}else{
ms.joinGroup(group);
}
 离开组并且关闭连接
public void leaveGroup(InetAddress address) throws IOException
public void leaveGroup(SocketAddress multicastAddress, NetworkInterface interface)throws IOException

这会通知本地组播路由器,告诉它停止向你发送数据。

 发送组播数据

用MulticastSocket发送数据与用DatagramSocket发送数据很相似。

try{
	InetAddress ia=InetAddress.getByname("experiment.mcast.net");
	byte[] data="dasfdsafsdaf\r\n".getBytes();
	DatagramPacket dp= new DatagramPacket(data,data.length,ia,port);
	MulticastSocekt ms= new MulticastSocket();
	ms.send(dp);
}catch(IOException ex){
	System.err.println(ex);
}

默认情况下TTL是1,可以在发送数据前调用setTimeToLive(int a)方法设置TTL,其中a的值在0-255之间,使用getTimeToLive获取TTL值。

回送模式

一台主机能否接受自己发出去的组播包,也就是组播包是否能够回送,这取决于具体的平台。

//true表示不希望接受
public void setLoopbackMode(boolean disable) throws SocketException
public boolean getLoopbackMode()throws SocketException

不过这只是一个建议,并非所有的系统都支持回送模式

网络接口

在多宿主机器中,setInterface()方法和setNetworkInterface()方法可以选择用于组播收发的网络接口:

public void setInterface(InetAddress address) throws SocketException
public InetAddress getInterface() throws SocketException
public void setNetworkInterface(NetworkInterface interface)throws SocketException
public NetworkInterface getNetworkInterface()throws SocketException

多宿主机器(Multi-homed Machine)是指一台拥有两个或两个以上网络接口的计算机,例如,两个或两个以上的以太网卡或者无线网卡。这些网络接口可以连接到相同或不同的网络

8. 案例实战

下面的程序主要是为了验证确实能够接受一个特定主机的组播数据(组播窃听器)。

public class QuizCardBuilder {
    public static void main(String[] args)  {
        InetAddress group;
        int port;
     try{
         group=InetAddress.getByName("239.255.255.250");
         port=1900;
     } catch (UnknownHostException e) {
         throw new RuntimeException(e);
     }
     MulticastSocket ms=null;
     try{
         ms=new MulticastSocket(port);
         ms.joinGroup(group);
         byte[] buffer=new byte[8192];
         while(true){
             DatagramPacket dp=new DatagramPacket(buffer, buffer.length);
             ms.receive(dp);
             String s=new String(dp.getData(),"8859_1");
             System.out.println(s);
         }
     } catch (IOException e) {
         throw new RuntimeException(e);
     }
    }
}

现在考虑如何发送组播数据

public class MulticastSender{
	public static void main(String[] args){
		InetAddress is=null;
		int port=0;
		byte ttl=(byte)1;
		try{
		 ia= InetAddress.getByname(args[0]);
		 port=InetAddress.parseInt(args[1]);
		 }catch(NumberFormatException| IndexOutofBoundException){
		 System.exit(0);
		 }
		 byte[] data="dasfsadfsdfsd\r\n".getBytes();
		 DatagramPacket dp=new DatagramPacket(data ,data.length, ia,port);
		 try(MulticastSocket ms= new MulticastSocket()){
		 	ms.setTimeToLive(ttl);
		 	ms.joinGroup(ia);
		 	for(int i=1;i<10;i++)
		 	{
		 	 ms.send(dp);
		 	 }
		 	ms.leaveGroup(ia);
		}catch(SocketException ex){
			System.err.println(ex);
		}catch(IOException ex){
			System.err.println(ex);
		}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/608127.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

LNMP平台搭建

文章目录 安装 Nginx 服务安装 MySQL 服务安装配置 PHP 解析环境 安装 Nginx 服务 systemctl stop firewalld systemctl disable firewalld setenforce 0安装依赖包 yum -y install pcre-devel zlib-devel gcc gcc-c make创建运行用户 useradd -M -s /sbin/nologin nginx编译…

ArduPilot之H743+BMI270x2+First Normal Takeoff

ArduPilot之H743BMI270x2First Normal Takeoff 1. 源由2. 正常起飞3. 问题汇总3.1 机架构型3.2 IMU对齐3.3 接收机3.4 GPS3.5 VTX3.6 电调3.7 PID 4. 总结5. 参考资料6. 附录6.1 补充AcroTrainer视频6.2 补充Acro视频 1. 源由 鉴于目前该飞控板子在ArduPilot开源社区尚未得到官…

Photoshop 批量照片转格式

Photoshop 批量照片转格式 文章目录 Photoshop 批量照片转格式前言一、打开Photoshop软件二、打开图像处理器三、参数设置四、运行 前言 在工作和学习中&#xff0c;我们可能会遇到需要处理多张图片、更改多张图片格式的情况&#xff0c;如果一张一张的进行处理是很麻烦浪费时…

一步一步从功能测试到测试开发,我这一路的坎坷谁能懂?

读者提问&#xff1a; 测试开发工程师到底是测试&#xff0c;还是开发 &#xff1f; 鱼鱼回答&#xff1a; 既是测试&#xff0c;也是开发。 首先&#xff0c;测试开发是测试工程师&#xff0c;他们是服务于业务测试同学的&#xff0c;目标是解决业务测试工程师的具体问题。…

基于flask的web应用开发——接受post请求

目录 0. 前言1. 了解post方法2. 在flask中实现3. 具体讲解 0. 前言 操作系统&#xff1a;Windows10 家庭版 开发环境&#xff1a;Pycahrm Comunity 2022.3 Python解释器版本&#xff1a;Python3.8 第三方库&#xff1a;flask 1. 了解post方法 POST是HTTP协议定义的一种请…

尚硅谷JUC极速版笔记

尚硅谷JUC极速版笔记 1、JUC概述1.1 进程和线程1.2 线程的状态&#xff08;6个&#xff09;1.3 wait和sleep1.4 并发与并行1.5 管程&#xff08;锁&#xff09;1.6 用户线程和守护线程 2、Lock接口2.1 复习synchronized&#xff08;java内置同步锁&#xff09;2.2 什么是Lock接…

03使用IDEA快速开发一个WEB应用的具体流程

使用集成开发环境实现web开发 集成开发工具很多&#xff0c;其中目前使用比较多的是IntelliJ IDEA和Eclipse IntelliJ IDEA(居多): JetBrain公司开发的收费软件, IDEA在提示功能方面要强于Eclipse使用起来更加智能更好用Eclipse(较少):Eclipse是IBM团队开发的, Eclipse寓意是…

ChatGPT 国内镜像网站独家汇总:发现最优秀的人工智能对话体验!

欢迎来到我们的 ChatGPT 镜像网站汇总博客&#xff01;在这个令人激动的人工智能时代&#xff0c;ChatGPT 作为一款顶尖的语言模型&#xff0c;已经引起了全球范围内的热议。但是&#xff0c;您是否曾经为了找到最佳的 ChatGPT 使用体验而苦苦搜寻&#xff1f;别担心&#xff0…

电商业务逻辑总结

一、后台模块:商品管理 1. 基本概念 ① spu: 标准化产品单元 不是一件具体的商品 eg iphone14 ② sku: 库存量单元 指的就是一件具体的商品 eg iphone14 128G 蓝色 ③ 销售属性 出现了商品详情页右侧的商品属性信息 ④ 平台属性 出现了商品详情页下…

vue 实现微信扫码登录的方法

一、准备工作&#xff1a; 1.微信公众号&#xff0c;扫码登录 2.域名&#xff0c;也就是域名解析&#xff08;public_domain&#xff09; 3.微信登录验证 4.配置微信扫码登录页面的代码&#xff0c;有了上面的准备工作&#xff0c;下面就可以开始编码了。 二、开发环境&#xf…

pinia的用法,一篇文章教你搞懂vuex的继任者pinia

一&#xff1a;pinia是什么&#xff1f; Pinia 是一个轻量级的、易于使用的 Vue.js 状态管理库。它是 Vuex 的一个替代方案&#xff0c;专为 Vue 3 设计&#xff0c;提供了更简单的 API 和更好的 TypeScript 支持。在你提供的代码中&#xff0c;Pinia 被用于管理应用程序的状态…

VAO、VBO、EBO简介

1.顶点缓冲对象(Vertex Buffer Objects, VBO) 顶点缓冲对象&#xff08;VBO&#xff09;的作用就是管理这个在GPU上创建的显存。使用这些缓冲对象的好处是我们可以一次性的发送一大批数据到显卡上&#xff0c;而不是每个顶点发送一次。从CPU把数据发送到显卡相对较慢&#xff…

java.security.MessageDigest的用法

java.security.MessageDigest MessageDigest的含义 message含义是:消息,信息 digest的含义是 digest 必应词典 n.摘要&#xff1b;文摘&#xff1b;概要&#xff1b;汇编 v.消化&#xff1b;领会&#xff1b;领悟&#xff1b;理解 海词 n. 摘要 vt. 消化&#xff1b;理解 vi…

进制转换(及规律)

Java变量命名规则和前端一样 约束 接口使用大驼峰 变量方法小托福 常量全大写 数值类型的 整型 byte a 1 所占空间1字节&#xff08;-128-127&#xff09; short a 1 所占空间2字节&#xff08;-32768-32767&#xff09;2^15-2^15-1 int a 1 所占空间4…

2023 华为 Datacom-HCIE 真题题库 11/12--含解析

单项选择题 1.[试题编号&#xff1a;190685] &#xff08;单选题&#xff09;通过iMasterNCE-Campus部署的虚拟化园区网络场景中&#xff0c;以下关于“添加设备”的描述中&#xff0c;错误的是哪一项&#xff1f; A、IMaster NCE-Campus支持通过设备角色添加设备 B、IMaster …

装饰器Python】进阶知识点

要明白装饰器首先得知道闭包 闭包&#xff1a;是内部函数对外部函数作用域的引用&#xff0c;并且一般外部函数函数的返回值是内部函数的函数名 def outer(x): # 外部函数 a x * 2 def inter(b) # 内部函数 …

手撕数据结构—单链表

✅作者&#xff1a;简单^不简单 &#x1f525;系列专栏&#xff1a;C语言数据结构 &#x1f496;如果文章有错误&#xff0c;时刻欢迎大家的指正。当然觉得博主的文章还不错的话&#xff0c;请点赞&#x1f44d;收藏⭐️留言&#x1f4dd; &#x1f4ac;格言&#xff1a;希望我…

设计模式之-模板方法模式C++实现与C++模板template用法

介绍 模板方法模式使用比较常见&#xff0c;也比较简单&#xff0c;模板方法模式是属于设计模式中的行为设计模式。行为设计模式是关注对象的行为或者交互方面的内容&#xff0c;主要涉及算法和对象之间的职责分配。 模板方法模式使用场景&#xff1a;在设计需求中&#xff0c;…

java并发编程:synchronized关键字与锁详解

文章目录 线程安全问题synchroinzed关键字几种锁Java对象头偏向锁轻量级锁自旋锁重量级锁锁升级的场景 JVM 是如何实现 synchronized 的&#xff1f;小结 这篇文章我们来聊一聊Java多线程里面的“锁”。 首先需要明确的一点是&#xff1a;Java多线程的锁都是基于对象的&#x…

御用飞场之惊险炸鸡寻根溯源

御用飞场之惊险炸鸡寻根溯源 1. 源由2. 分析3. 证据4. 总结5. 补充&#xff1a;BetaFlight Mark4 自锁螺母桨叶松动 炸机瞬间 1. 源由 这个炸鸡的原因千奇百怪&#xff0c;不过最终的结果都是相似的。 如果能很好的找到根原因&#xff0c;相对来说&#xff0c;今后炸鸡的概…