本文的理论和代码摘录于《疯狂Java讲义》
http://book.51cto.com/art/201203/322560.htm,测试部分的截图是本人增加的。
1.理论
DatagramSocket只允许数据报发送给指定的目标地址,而MulticastSocket可以将数据报以广播方式发送到多个客户端。
若要使用多点广播,则需要让一个数据报标有一组目标主机地址,当数据报发出后,整个组的所有主机都能收到该数据报。IP多点广播实现了将单一信息发送到多个接收者的广播,其思想是设置一组特殊网络地址作为多点广播地址,每一个多点广播地址都被看做一个组,当客户端需要发送、接收广播信息时,加入到该组即可。
多播组通过 D 类 IP 地址和标准 UDP 端口号指定。D 类 IP 地址在 224.0.0.0 和 239.255.255.255 的范围内(包括两者)。地址 224.0.0.0 被保留,不应使用。多点广播示意图如图所示。
MulticastSocket是DatagramSocket的一个子类,当要发送一个数据报时,可以使用随机端口创建MulticastSocket,也可以在指定端口创建MulticastSocket。
如果创建仅用于发送数据报的MulticastSocket对象,则使用默认地址、随机端口即可。但如果创建接收用的MulticastSocket对象,则该MulticastSocket对象必须具有指定端口,否则发送方无法确定发送数据报的目标端口。
MulticastSocket比DatagramSocket多了一个setTimeToLive(int ttl)方法,该ttl参数用于设置数据报最多可以跨过多少个网络。
当ttl的值为0时,指定数据报应停留在本地主机;
当ttl的值为1时,指定数据报发送到本地局域网;
当ttl的值为32时,意味着只能发送到本站点的网络上;
当ttl的值为64时,意味着数据报应保留在本地区;
当ttl的值为128时,意味着数据报应保留在本大洲;
当ttl的值为255时,意味着数据报可发送到所有地方;
在默认情况下,该ttl的值为1。
2.编码
下面程序使用MulticastSocket实现了一个基于广播的多人聊天室。程序只需要一个MulticastSocket,两个线程,其中MulticastSocket既用于发送,也用于接收;一个线程负责接收用户键盘输入,并向Multicast Socket发送数据,另一个线程则负责从MulticastSocket中读取数据。
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.util.Scanner;
public class MulticastSocketTest implements Runnable {
// 使用常量作为本程序的多点广播IP地址
private static final String BROADCAST_IP = "230.0.0.1";
// 使用常量作为本程序的多点广播目的地端口
public static final int BROADCAST_PORT = 30000;
// 定义每个数据报的最大大小为4KB
private static final int DATA_LEN = 4096;
// 定义本程序的MulticastSocket实例
private MulticastSocket socket = null;
private InetAddress broadcastAddress = null;
// 定义接收网络数据的字节数组
byte[] inBuff = new byte[DATA_LEN];
// 以指定字节数组创建准备接收数据的DatagramPacket对象
private DatagramPacket inPacket = new DatagramPacket(inBuff, inBuff.length);
// 定义一个用于发送的DatagramPacket对象
private DatagramPacket outPacket = null;
public void init() throws IOException {
try {
// 创建键盘输入流
Scanner scan = new Scanner(System.in);
// 创建用于发送、接收数据的MulticastSocket对象
// 由于该MulticastSocket对象需要接收数据,所以有指定端口
socket = new MulticastSocket(BROADCAST_PORT);
broadcastAddress = InetAddress.getByName(BROADCAST_IP);
// 将该socket加入指定的多点广播地址
socket.joinGroup(broadcastAddress);
// 设置本MulticastSocket发送的数据报会被回送到自身
socket.setLoopbackMode(false);
// 初始化发送用的DatagramSocket,它包含一个长度为0的字节数组
outPacket = new DatagramPacket(new byte[0], 0, broadcastAddress,
BROADCAST_PORT);
// 启动以本实例的run()方法作为线程执行体的线程
new Thread(this).start();
// 不断地读取键盘输入
while (scan.hasNextLine()) {
// 将键盘输入的一行字符串转换成字节数组
byte[] buff = scan.nextLine().getBytes();
// 设置发送用的DatagramPacket里的字节数据
outPacket.setData(buff);
// 发送数据报
socket.send(outPacket);
}
} finally {
socket.close();
}
}
public void run() {
try {
while (true) {
// 读取Socket中的数据,读到的数据放在inPacket所封装的字节数组里
socket.receive(inPacket);
// 打印输出从socket中读取的内容
System.out.println("聊天信息:"
+ new String(inBuff, 0, inPacket.getLength()));
}
}
// 捕获异常
catch (IOException ex) {
ex.printStackTrace();
try {
if (socket != null) {
// 让该Socket离开该多点IP广播地址
socket.leaveGroup(broadcastAddress);
// 关闭该Socket对象
socket.close();
}
System.exit(1);
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws IOException {
new MulticastSocketTest().init();
}
}
3.测试
下面我们测试一下,打开3个MulticastSocketTest。随便哪个Client发条消息,所有Client包括自己都可以收到这条消息。
用Process Explorer监控一下端口可以发现,每个程序都开启了30000端口。
这点有点意外,因为我们发现同时开2个UdpServer是会报错的,说端口已经被绑定。而MulticastSocket则不会报错。我们也可以换个角度思考问题,一个数据报被要求发送到多播地址的30000号端口,这样的话其他成员要接收到这个数据的话,只有去30000号端口去拿了,其他端口是拿不到的。局域网中如果是多台计算机的话,每台各自开启一个30000号端口肯定是没问题的,至于同一台机器上为什么没问题我就不得而知了,可能得要研究底层的网络协议去了。如果哪位大侠知道的话还望不吝指教。
- 大小: 4.4 KB
- 大小: 65.1 KB
- 大小: 14.4 KB
分享到:
相关推荐
本文将详细介绍如何利用JDK自带的算法实现AES加解密,并结合Base64编解码进行数据处理。 首先,AES是一种分组密码,它以128位为一个数据块进行加密,支持128、192和256位的密钥长度。在JDK中,AES加解密的核心类...
分别使用jdk和cglib实现动态代理,包含UML图。还有相关的博客链接:http://blog.csdn.net/y_love_f/article/details/46345581.博客中有具体的代理解释
JDK11使用MapStruct
标题中的"window JDK1.5 32位 绿色免安装版"指的是适用于Windows操作系统的32位版本的JDK 1.5,它是一个便携式版本,无需正式安装即可使用。这种绿色免安装版通常是为了方便开发者在不同机器间快速切换工作环境,或...
JDK11安装包,JDK11安装包JDK11安装包,JDK11安装包JDK11安装包,JDK11安装包JDK11安装包,JDK11安装包JDK11安装包,JDK11安装包JDK11安装包,JDK11安装包JDK11安装包,JDK11安装包JDK11安装包,JDK11安装包JDK11...
jdk8帮助文档jdk8帮助文档jdk8帮助文档jdk8帮助文档jdk8帮助文档jdk8帮助文档jdk8帮助文档jdk8帮助文档jdk8帮助文档jdk8帮助文档jdk8帮助文档jdk8帮助文档jdk8帮助文档jdk8帮助文档jdk8帮助文档jdk8帮助文档jdk8帮助...
mac系统jdk1.8安装包!mac系统jdk1.8安装包!mac系统jdk1.8安装包!mac系统jdk1.8安装包!mac系统jdk1.8安装包!mac系统jdk1.8安装包!mac系统jdk1.8安装包!mac系统jdk1.8安装包!mac系统jdk1.8安装包!mac系统jdk...
JDK7安装包.zip\JDK7安装包.zip\JDK7安装包.zip\JDK7安装包.zip\JDK7安装包.zip JDK7安装包.zip\JDK7安装包.zip\JDK7安装包.zip\JDK7安装包.zip\JDK7安装包.zip JDK7安装包.zip\JDK7安装包.zip\JDK7安装包.zip\JDK7...
jdk7 jdk8 jdk9 jdk10 jdk11 jdk12 jdk13 jdk14 (win-64位) 资源共享
此外,模块化系统(Project Jigsaw)虽然在JDK 8中未完全实现,但为后续版本奠定了基础。 JDK 11是2018年的LTS版本,它在JDK 8的基础上继续优化并增加了新特性。例如,正式引入了模块化系统(Jigsaw),这使得大型...
jdk7 jdk8 jdk9 jdk10 jdk11 jdk12 jdk13 jdk14 (linux-rpm 64位) 资源共享
此外,方法引用来替代匿名内部类,以及默认方法的引入,使得接口可以拥有默认实现,极大地丰富了接口的使用场景。 在性能方面,JDK 1.8相比1.6有了显著提升。JVM的改进包括G1垃圾收集器的增强,使得大内存应用的...
默认方法通过在方法声明前加上`default`关键字实现,可以有实现代码,这样接口的实现类可以选择重写或者直接使用默认实现。 ### 6. **日期和时间API的改进** JDK 8替换原有的`java.util.Date`和`java.util.Calendar...
JDK11、JDK11、JDK11、JDK11、JDK11、JDK11、JDK11、JDK11、JDK11、JDK11、JDK11、JDK11、JDK11、JDK11、JDK11、JDK11、JDK11、JDK11、JDK11、JDK11、JDK11、JDK11、JDK11、JDK11、JDK11、JDK11、JDK11、JDK11、JDK...
本文将详细介绍如何在Linux环境下更换JDK,并进一步介绍如何更改WebLogic服务器所使用的JDK。 #### 二、Linux系统更换JDK ##### 1. 查看当前JDK安装情况 首先,需要检查当前系统是否已安装JDK以及其版本信息。 - ...
当JDK用于后台服务(如Tomcat或Jenkins)时,需要确保服务启动脚本也使用了正确的JDK环境。可以通过修改服务启动脚本中的环境变量或链接到正确的`java`可执行文件来实现。 7. **安全与更新** 虽然JDK 11是一个LTS...
在 Windows Server 2003 系统上,使用 JDK5.0,最大可设置为 1478m。 在设置堆大小时,需要考虑多方面的因素,例如操作系统、物理内存、虚拟内存等。典型的堆大小设置为:-Xmx3550m -Xms3550m -Xmn2g -Xss128k。...
同时,为了在不同的项目中切换不同版本的JDK,可以利用工具如JEnv或手动调整系统路径来实现。 总结这三个版本,JDK6奠定了现代Java的基础,JDK7带来了语言层面的改进,而JDK8则引领了Java向函数式编程的转变。这些...
总结来说,虽然JDK 1.6本身没有内置Base64支持,但通过引入Apache Commons Codec库,我们可以轻松地在JDK 1.6环境中实现Base64编码和解码。这对于需要处理Base64数据的项目至关重要,尤其是在与旧系统兼容或维护老...