现在的位置: 首页 > 综合 > 正文

多播

2013年09月15日 ⁄ 综合 ⁄ 共 5326字 ⁄ 字号 评论关闭

4.3.2 多播

与广播一样,多播与单播之间的一个主要区别是地址的形式。一个多播地址指示了一组接收者。IP协议的设计者为多播分配了一定范围的地址空
间,IPv4中的多播地址范围是224.0.0.0到239.255.255.255,IPv6中的多播地址是任何由FF开头的地址。除了少数系统保留的
多播地址外,发送者可以向以上范围内的任何地址发送数据。Java中多播应用程序主要通过MulticastSocke实例进行通信,它是
DatagramSocket的一个子类。重点需要理解的是,一个MulticastSocket实例实际上就是一个UDP套接字
(DatagramSocket),其包含了一些额外的可以控制的多播特定属性。我们的下一个例子实现了投票信息的多播发送者和接收者。

VoteMulticastSender.java

0 import java.io.IOException;
1 import java.net.DatagramPacket;
2 import java.net.InetAddress;
3 import java.net.MulticastSocket;
4
5 public class VoteMulticastSender {
6
7 public static final int CANDIDATEID = 475;
8
9 public static void main(String args[]) throws IOException {
10
11 if ((args.length < 2) || (args.length > 3)) { // Test # of args
12 throw new IllegalArgumentException("Parameter(s):
[]");
13 }
14
15 InetAddress destAddr = InetAddress.getByName(args[0]); // Destination
16 if (!destAddr.isMulticastAddress()) { // Test if multicast address
17 throw new IllegalArgumentException("Not a multicast address");
18 }
19
20 int destPort = Integer.parseInt(args[1]); // Destination port
21 int TTL = (args.length == 3) ? Integer.parseInt(args[2]) : 1; // Set TTL
22
23 MulticastSocket sock = new MulticastSocket();
24 sock.setTimeToLive(TTL); // Set TTL for all datagrams
25
26 VoteMsgCoder coder = new VoteMsgTextCoder();
27
28 VoteMsg vote = new VoteMsg(true, true, CANDIDATEID, 1000001L);
29
30 // Create and send a datagram
31 byte[] msg = coder.toWire(vote);
32 DatagramPacket message = new DatagramPacket(msg,
msg.length, destAddr, destPort);
33 System.out.println("Sending Text-Encoded Request
(" + msg.length + " bytes): ");
34 System.out.println(vote);
35 sock.send(message);
36
37 sock.close();
38 }
39 }

VoteMulticastSender.java

我们的单播发送者和多播发送者仅有的重要区别是:1)对给定地址是否是多播地址进行了验证,2)为多播数据报文设置了初始的TTL值(生命周期,
Time To
Live)。每个IP数据报文中都包含了一个TTL,它被初始化为某个默认值,并在每个路由器转发该报文时递减(通常是减1)。当TTL值减为0时,就丢
弃该数据报文。通过设置TTL的初始值,我们可以限制数据包从发送者开始所能传递到的最远距离。[ ]

与广播不同,网络多播只将消息副本发送给指定的一组接收者。这组接收者叫做多播组(multicast
group),通过共享的多播(组)地址确定。接收者需要一种机制来通知网络它对发送到某一特定地址的消息感兴趣,以使网络将数据包转发给它。这种通知机
制叫做加入一组(joining a
group),可以由MulticastSocket类的joinGroup()方法实现。我们的多播接收者加入了一个特定的组,接收并打印该组的一条多
播消息,然后退出。

VoteMulticastReceiver.java

0 import java.io.IOException;
1 import java.net.DatagramPacket;
2 import java.net.InetAddress;
3 import java.net.MulticastSocket;
4 import java.util.Arrays;
5
6 public class VoteMulticastReceiver {
7
8 public static void main(String[] args) throws IOException {
9
10 if (args.length != 2) { // Test for correct # of args
11 throw new IllegalArgumentException("Parameter(s):
");
12 }
13
14 InetAddress address = InetAddress.getByName
(args[0]); // Multicast address
15 if (!address.isMulticastAddress()) { // Test if multicast address
16 throw new IllegalArgumentException("Not a multicast address");
17 }
18
19 int port = Integer.parseInt(args[1]); // Multicast port
20 MulticastSocket sock = new MulticastSocket(port); // for receiving
21 sock.joinGroup(address); // Join the multicast group
22
23 VoteMsgTextCoder coder = new VoteMsgTextCoder();
24
25 // Receive a datagram
26 DatagramPacket packet = new DatagramPacket(new byte
[VoteMsgTextCoder.MAX_WIRE_LENGTH],
27 VoteMsgTextCoder.MAX_WIRE_LENGTH);
28 sock.receive(packet);
29
30 VoteMsg vote = coder.fromWire(Arrays.copyOfRange
(packet.getData(), 0, packet
31 .getLength()));
32
33 System.out.println("Received Text-Encoded Request
(" + packet.getLength()
34 + " bytes): ");
35 System.out.println(vote);
36
37 sock.close();
38 }
39 }

VoteMulticastReceiver.java

我们的多播和单播接收者唯一的重要区别是,多播接收者表明希望从哪个多播地址接收数据来加入多播组。本书的网站上还有另一个多播发送者和接收者的例
子。MulticastImageSender.java将一组由命令行参数指定的图片(JPEG或GIF)以3秒的时间间隔传输。
MulticastImageReceiver.java则接收每一个图片并在窗口中显示。

多播数据报文实际上可以通过DatagramSocket中发送,只需要简单地指定一个多播地址。不过MulticastSocket还有一些
DatagramSocket没有的能力,包括1)允许指定数据报文的TTL,和2)允许指定和改变通过哪个接口将数据报文发送到组(接口由其互联网地址
确定)。另一方面,一个多播消息接收者必须使用MulticastSocket来接收数据,因为它需要用到MulticastSocket加入组的功能。

MulticastSocket是DatagramSocket的一个子类,因此它提供了DatagramSocket的全部方法。在此,我们只对MulticastSocket中特有或修改过的方法进行介绍。

MulticastSocket: 创建

MulticastSocket()
MulticastSocket(int localPort)
MulticastSocket(SocketAddress bindaddr)

这些构造函数用来创建一个具有多播功能的UDP套接字。如果没有指定本地端口或指定为0,套接字将绑定到任意一个可以的本地端口。如果指定了地址,该套接字则只能从所指定的地址接收消息。

如果要接收数据报文,我们必须加入到一个多播组中。

MulticastSocket: 组管理

void joinGroup(InetAddress groupAddress)
void joinGroup(SocketAddress mcastaddr, NetworkInterface netIf)
void leaveGroup(InetAddress groupAddress)
void leaveGroup(SocketAddress mcastaddr, NetworkInterface netIf)

joinGroup()和leaveGroup()方法用于管理该套接字的多播组成员资格信息。一个套接字可以同时为多个多播组成员。如果套接字加
入一个已经加入了的组,或在没有加入任何组的情况下离开一个组,都可能抛出异常。还可以选择性地指定从哪个接口加入或离开多播组。

MulticastSocket: 设置/获取多播选项

int getTimeToLive()
void setTimeToLive(int ttl)
boolean getLoopbackMode()
void setLoopbackMode(boolean disable)
InetAddress getInterface()
NetworkInterface getNetworkInterface()
void setInterface(InetAddress inf)
void setNetworkInterface(NetworkInterface netIf)

getTimeToLive()
和setTimeToLive()方法用于设置通过该套接字发送的所有数据报文的生存周期。如果套接字启用了回环模式,则会接收到自己发送的数据报文。
getLoopbackMode()和setLoopbackMode()方法用于为多播套接字设置回环模式,将其设置为true时表示关闭回环模式。
getInterface()方法,setInterface()方法,getNetworkInterface()以及
setNetworkInterface()方法用于设置从哪个接口发送多播数据包。这主要用在有多个接口的主机上。默认的多播接口是与平台独立的。

决定使用广播还是使用多播需要考虑多方面的因素,包括接收者的网络地址和通信双方的知识。互联网广播的范围是限定在一个本地广播网络之内的,并对广
播接收者的位置进行了严格的限制。多播通信可能包含网络中任何位置的接收者,[
]因此多播有个好处就是它能够覆盖一组分布在各处的接收者。IP多播的不足在于接收者必须知道要加入的多播组的地址。而接收广播信息则不需要指定地址信
息。在某些情况下,广播是一个比多播更好更易于发现的机制。所有主机在默认情况下都可以接收广播,因此,在一个网络中向所有主机询问"打印机在哪儿?"是
件容易的事。

UDP单播、多播和广播都基于底层UDP套接字实现。这些实现的大部分语义都是,一个UDP数据报文将发送到所有与数据包的目标端口绑定的套接字
上。也就是说,如果有一个DatagramSocket或MulticastSocket实例与本地端口X相绑定(没有指定本地地址,即野报文),地址为
Y的主机可能会在以下几种情况下收到发向端口X的UDP数据报文:1)目的地址为Y的单播,2)主机Y上所有应用程序都加入了发送到的多播组,或3)向能
够到达主机Y的网络进行广播。接收者可以使用connect()方法来限定数据报文的源地址和端口。同时,一个DatagramSocket实例也可以指
定本地单播地址,这将阻止多播和广播数据包的转发。目的地址验证的例子见UDPEchoClientTimeout.java,数据报文分成多路处理的详
情见第6.5节。

抱歉!评论已关闭.