目前大多数操作系统和网络路由器均提供了组播功能,其将决定如何高效地将消息转移到各个主机。IP组播建立在UDP基础上,其比单播通信宽,但比广播通信要窄且目标更明确。组播将数据从一个主机发送给多个不同的主机,数据只传送到加入某个特定小组的客户端,这和公开会议相类似。组播节省带宽的做法:数据在每个路由干路上只有一个副本在传输,仅到达目的小组时才会进行复制分发。
组播大多数工作都由路由器完成,这对用户是透明的。应用程序只是将数据包发送给一个组播地址,路由器将确保数据包被分发到该小组中的所有主机。组播地址是一组主机共享地址,IPv4组播地址是224.0.0.0/4,IPv6组播地址是FF00::/8。组播中的成员是开放的,主机可以随时进入或者离开小组。小组可以是永久的也可是临时的,永久的小组分配的地址保持不变,而不论小组中是否有成员,但大多数小组是临时的,只在有成员存在时小组才存在,小面是组播地址分配:
- 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为本地管理组播地址,仅在特定的本地范围内有效。
要创建一个组播组,我们可以在224.0.2.0~238.255.255.255之间随机选择一个地址,向其发送数据。当一台主机希望向组播组发送数据时,它只要将数据放在组播组数据报中,组播组数据报就是发送到组播组的UDP包。在Java中,创建一个MulticastSocket,让这个socket加入到小组,就可以接收到小组中的信息了,不再希望接收数据时离开这个小组即可。但是向这个小组发送消息并不一定要加入这个小组。下面是daytime组播示例代码:
-
MulticastListener.java
,小组收听成员
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
/**
* Created by Cheney Hwang on 2017/5/10.
*/
public class MulticastListener {
public final static int PORT = 5555;
public final static String GROUP = "225.0.0.0";
public static void main(String[] args) {
byte[] now = new byte[64];
MulticastSocket socket = null;
InetAddress group = null;
try {
socket = new MulticastSocket(PORT);
group = InetAddress.getByName(GROUP);
socket.joinGroup(group);//只有加入组播才可以收数据,但是无需加入组播就可发数据
while (true) {
DatagramPacket packet = new DatagramPacket(now, now.length);
socket.receive(packet);
String nowStr = new String(packet.getData(), "US-ASCII");
System.out.println(nowStr);
}
} catch (IOException ex) {
//创建socket出错,很可能是端口占用
} finally {
if (socket != null) {
try {
socket.leaveGroup(group);
socket.close();
} catch (IOException ex) {
//如果没有加入group不会报错,但是如果group不是组播地址将报错
}
}
}
}
}
MulticastSpeaker.java
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.util.Date;
/**
* Created by Cheney Hwang on 2017/5/10.
*/
public class MulticastSpeaker {
public final static int PORT = 5555;
public final static String GROUP = "225.0.0.0";
public static void main(String[] args) {
try {
byte[] now = new Date().toString().getBytes("US-ASCII");
DatagramPacket packet = new DatagramPacket(now, now.length,
InetAddress.getByName(GROUP), PORT);
MulticastSocket socket = new MulticastSocket();//向组播中发送数据无需加入组
socket.send(packet);
} catch (IOException ex) {
}
}
}