目前大多数操作系统和网络路由器均提供了组播功能,其将决定如何高效地将消息转移到各个主机。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) {

        }
    }
}