这些Java教程是针对JDK 8编写的。本页面描述的示例和实践不利用后续版本中引入的改进,并且可能使用不再可用的技术。
请参阅Java语言更改以获取Java SE 9及后续版本中更新的语言特性的摘要。
请参阅JDK发行说明以获取有关所有JDK版本的新功能、增强功能和已删除或不推荐选项的信息。
除了DatagramSocket,它允许程序之间发送数据包,java.net还包括一个名为MulticastSocket的类。这种类型的套接字用于客户端侦听服务器广播给多个客户端的数据包。
让我们重写报价服务器,以便将DatagramPacket广播给多个接收者。新服务器不再将报价发送给发出请求的特定客户端,而是需要定期广播报价。客户端需要修改,以被动地侦听报价,并在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的端口号实际上并不重要,因为客户端从不向服务器发送任何数据。
MulticastServerThread中唯一显式实现的方法是它的run方法。这个run方法与QuoteServerThread中的方法之间的差异以粗体显示:
public void run() {
while (moreQuotes) {
try {
byte[] buf = new byte[256];
// 不等待请求...只发送报价
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,特别是用于构造DatagramPacket的InetAddress和端口。回想一下,之前的例子是从客户端发送给服务器的数据包中获取InetAddress和端口号。这是因为服务器需要直接回复给客户端。现在,服务器需要处理多个客户端。所以这次InetAddress和端口号都是硬编码的。
硬编码的端口号是4446(客户端必须有一个绑定到该端口的MulticastSocket)。DatagramPacket的硬编码InetAddress是"203.0.113.0",是一个组标识符(而不是运行单个客户端的机器的Internet地址)。此特定地址是从保留用于此目的的地址中任意选择的。
以这种方式创建的DatagramPacket将发送到所有侦听端口号4446并且是"203.0.113.0"组的成员的客户端。
要侦听端口号4446,新的客户端程序只需使用该端口号创建其MulticastSocket。要成为"203.0.113.0"组的成员,客户端调用MulticastSocket的joinGroup方法,并传入标识组的InetAddress。现在,客户端已设置好接收发送到指定端口和组的DatagramPacket。以下是新客户端程序的相关代码(还重新编写为被动接收报价而不是主动请求报价)。粗体语句是与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("此刻的报价:" + received);
}
socket.leaveGroup(group);
socket.close();
请注意,服务器使用DatagramSocket将客户端接收到的数据包广播到MulticastSocket。或者,它也可以使用MulticastSocket。服务器用于发送DatagramPacket的套接字并不重要。在广播数据包时,重要的是DatagramPacket中包含的寻址信息,以及客户端用于侦听的套接字。
运行MulticastServer和几个客户端,观察所有客户端都获得相同的报价。