多播

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節。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章