Broadcast 到多个收件人
除了DatagramSocket
(允许程序彼此发送数据包)之外,java.net 还包括一个名为MulticastSocket
的类。这种套接字用于 Client 端,以侦听服务器 Broadcast 到多个 Client 端的数据包。
让我们重写报价服务器,以便它向多个收件人 BroadcastDatagramPacket
。现在,新服务器不再需要将报价发送给发出请求的特定 Client 端,而是需要定期 Broadcast 报价。需要修改 Client 端,以便它被动地监听报价,并在MulticastSocket
上监听报价。
此示例由三个类组成,这三个类是对上一个示例MulticastServer,MulticastServerThread和MulticastClient的三个类的修改。本讨论重点介绍了这些类的有趣部分。
这是服务器主程序的新版本。此代码与先前版本QuoteServer
之间的区别以粗体显示:
import java.io.*;
public class MulticastServer {
public static void main(String[] args) throws IOException {
new MulticastServerThread().start();
}
}
基本上,服务器获得了一个新名称,并创建了一个MulticastServerThread
而不是QuoteServerThread
。现在让我们看一下包含服务器核心的MulticastServerThread
。这是它的类声明:
public class MulticastServerThread extends QuoteServerThread {
// ...
}
我们将该类作为QuoteServerThread
的子类,以便可以使用构造函数,并继承一些成员变量和getNextQuote
方法。回想一下QuoteServerThread
创建绑定到端口 4445 的DatagramSocket
并打开报价文件。在此示例中,DatagramSocket
的端口号实际上并不重要,因为 Client 端从不向服务器发送任何内容。
MulticastServerThread
中明确实现的唯一方法是其run
方法。 run
方法与QuoteServerThread
中的方法之间的区别以粗体显示:
public void run() {
while (moreQuotes) {
try {
byte[] buf = new byte[256];
// don't wait for request...just send a quote
String dString = null;
if (in == null)
dString = new Date().toString();
else
dString = getNextQuote();
buf = dString.getBytes();
InetAddress group = InetAddress.getByName("203.0.113.0");
DatagramPacket packet;
packet = new DatagramPacket(buf, buf.length, group, 4446);
socket.send(packet);
try {
sleep((long)Math.random() * FIVE_SECONDS);
}
catch (InterruptedException e) { }
}
catch (IOException e) {
e.printStackTrace();
moreQuotes = false;
}
}
socket.close();
}
有趣的变化是DatagramPacket
的构造方式,尤其是InetAddress
和用于构造DatagramPacket
的端口。回想一下,前面的示例从 Client 端发送到服务器的数据包中检索了InetAddress
和端口号。这是因为服务器需要直接回复 Client 端。现在,服务器需要寻址多个 Client 端。因此,这次InetAddress
和端口号都是硬编码的。
硬编码的端口号是 4446(Client 端必须为此端口绑定MulticastSocket
)。 DatagramPacket
的硬编码InetAddress
是“ 203.0.113.0”,并且是组标识符(而不是运行单个 Client 端的计算机的 Internet 地址)。为此,从保留位置中任意选择了此特定地址。
以这种方式创建的DatagramPacket
面向所有监听端口号 4446 的“ 203.0.113.0”组成员的所有 Client 端。
要监听端口号 4446,新的 Client 端程序刚刚使用该端口号创建了其MulticastSocket
。为了成为“ 203.0.113.0”组的成员,Client 端使用标识该组的InetAddress
调用MulticastSocket
的joinGroup
方法。现在,将 Client 端设置为接收指定端口和组的DatagramPacket
。这是新 Client 端程序中的相关代码(该代码也被重写为被动接收报价,而不是主动请求报价)。粗体语句是与MulticastSocket
交互的语句:
MulticastSocket socket = new MulticastSocket(4446);
InetAddress group = InetAddress.getByName("203.0.113.0");
socket.joinGroup(group);
DatagramPacket packet;
for (int i = 0; i < 5; i++) {
byte[] buf = new byte[256];
packet = new DatagramPacket(buf, buf.length);
socket.receive(packet);
String received = new String(packet.getData());
System.out.println("Quote of the Moment: " + received);
}
socket.leaveGroup(group);
socket.close();
请注意,服务器使用DatagramSocket
BroadcastClient 端通过MulticastSocket
接收的数据包。或者,它可以使用MulticastSocket
。服务器用于发送DatagramPacket
的套接字并不重要。Broadcast 数据包时,重要的是DatagramPacket
中包含的寻址信息以及 Client 端用来侦听它的套接字
Try this:
运行MulticastServer
和几个 Client 端。观看所有 Client 如何获得相同的报价。