我们都知道,网络的通信模式可以分为单播、广播和多播:
单播:点到点的通信方式
多播:点到多点的通信方式
汇播:多点到一点的通信方式
群播:多点到多点的通信方式
广播:点到所有节点的通信方式
常用的是单播、多播和广播
之前我们将的 TCP Socket 和 UDP Socket 都是点到点的,属于单播,就好比两个人交谈,交谈的内容只有他俩知道(当然也有别人偷听,这里不算)。
多播就好像是群组聊天,只有特定的人才能知道聊天内容。
广播就是大喇叭了,所有人都能听到。
在 TCP/IP 协议栈中,传输层只有 UDP 可以广播,广播数据包不经过路由器,只在同一个局域网内部广播。
IPv4 的广播地址是 255.255.255.255.
广播可以使得通信的效率提高,因为它不光三七二十一,直接把数据报发送到每一个客户端,这样同样也会带来问题,那就是占用贷款,并且没有针对性,所有客户端都必须强制接收。
代码就不列了,只需要把之前的 UDP Socket 代码中的 IP 换成广播地址就 OK。
多播其实和广播类似,只是多播指定了一组接受者,只有指定的接受者可以接收到数据报。
IPv4 中的多播地址范围是 224.0.0.0 到 239.255.255.255,地址 224.0.0.0 被保留,不应使用。发送者可以向以上范围内的任何地址发送数据。
Java 中多播应用程序主要通过 MulticastSocket,它是 DatagramSocket 的子类,所以说其本质还是 DatagramSocket,只是另外包含了一些额外的可以控制的多播特定属性。
构造方法:
MulticastSocket()
创建多播套接字。
MulticastSocket(int port)
创建多播套接字并将其绑定到特定端口。
MulticastSocket(SocketAddress bindaddr)
创建绑定到指定套接字地址的 MulticastSocket。
查询方法:
getInterface()
获取用于多播数据包的网络接口的地址。
getLoopbackMode()
获取多播数据报的本地回送的设置。
getNetworkInterface()
获取多播网络接口集合。
getTimeToLive()
获取在套接字上发出的多播数据包的默认生存时间。
设置方法:
setInterface(InetAddress inf)
设置多播网络接口,供其行为将受网络接口值影响的方法使用。
setLoopbackMode(boolean disable)
启用/禁用多播数据报的本地回送。
setNetworkInterface(NetworkInterface netIf)
指定在此套接字上发送的输出多播数据报的网络接口。
setTimeToLive(int ttl)
设置在此 MulticastSocket 上发出的多播数据包的默认生存时间,以便控制多播的范围。
其他方法:
joinGroup(InetAddress mcastaddr)
加入多播组。
joinGroup(SocketAddress mcastaddr, NetworkInterface netIf)
加入指定接口上的指定多播组。
leaveGroup(InetAddress mcastaddr)
离开多播组。
leaveGroup(SocketAddress mcastaddr, NetworkInterface netIf)
离开指定本地接口上的多播组。
我们都知道,UDP Socket 是不区分客户端和服务端的,只能区分接收端和发送端,MulticastSocket 又是 DatagramSocket 的子类,所以它也是一样,只要该客户端加入了多播组,那么它就能接收来自该组其他客户端发送的消息,同时也能发送消息给该组的其他客户端。
客户端通过 leaveGroup 方法脱离多播组,脱离之后,就不会再收到该组成员发送的消息了。
多播数据包有一个默认生存时间
即 TTL,用以控制多播的范围,每当有路由器转发该报文时,TTL减1,直到减为0时,生命周期结束,报文即时没有到达目的地,也立即宣布死亡。该时间必须在 0~255 之间,可以通过 setTimeToLive 方法设置,通过 getTimeToLive 方法获取。
一个简单的例子:
发送端
public class MulticastSocketSender {
public static void main(String[] args) {
try {
byte[] bytes = "我想要怒放的生命".getBytes();
MulticastSocket socket = new MulticastSocket();
DatagramPacket packet = new DatagramPacket(bytes, bytes.length, InetAddress.getByName("224.0.0.1"), 6789);
socket.joinGroup(InetAddress.getByName("224.0.0.1"));
socket.send(packet);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
接收端
public class MulticastSocketReceiver {
public static void main(String[] args) {
try {
byte[] bytes = new byte[1024];
MulticastSocket socket = new MulticastSocket(6789);
DatagramPacket packet = new DatagramPacket(bytes, bytes.length);
socket.joinGroup(InetAddress.getByName("224.0.0.1"));
socket.receive(packet);
byte[] data = packet.getData();
System.out.println(new String(data, 0, data.length));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}