应用软件对网络接入的需求比以往任何时候都要迫切。仿佛一夜之间,家里所有东西都要联网了。在旧版Java中,套接字和通道结合得并不是很好,将它们两个配合在一起是件棘手的事情。因此Java 7推出了NetworkChannel
,把Socket
和Channel
结合到一起,让开发人员可以轻松应对。
编写底层网络代码算是专业领域。如果你的工作领域与此无关,完全可以跳过这一节!但如果恰好你就是干这个的,你可以在本节对Java 7的新特性有一个初步了解。
我们先来看看套接字和通道在Javadoc中的定义,重温一下它们在Java中扮演的角色:
java.nio.channels
包 定义通道,表示连接到执行I/O操作的实体,比如文件和套接字。定义用于多路传输、非阻塞I/O操作的选择器。java.net.Socket
类 该类实现了客户端套接字(也称为“套接字”)。套接字是两个机器间通信的端点。
在旧版Java中,为了执行I/O操作,比如向TCP端口中写入数据,你需要将通道绑定到Socket
的实现类上,但Channel
和Socket
彼此之间却有“代沟”:
- 在旧版Java中,为了配置套接字选项和绑定在套接字上,必须把通道和套接字的API整合在一起;
- 在旧版Java中,不能利用平台特定的套接字行为。
让我们来看看新接口NetworkChannel
和其子接口MulticastChannel
对这两个领域做的“整理”工作。
2.6.1 NetworkChannel
新接口java.nio.channels.NetworkChannel
代表一个连接到网络套接字通道的映射。它定义了一组实用的方法,比如查看及设置通道上可用的套接字选项等。下面的代码运用这些方法输出互联网套接字地址在端口3080上所支持的选项,设置IP服务条款选项以及确认套接字通道上的SO_KEEPALIVE
选项。
代码清单2-10 NetworkChannel
选项
SelectorProvider provider = SelectorProvider.provider;
try
{
/**将NetworkChannel绑定到端口3080上*/
NetworkChannel socketChannel = provider.openSocketChannel;
SocketAddress address = new InetSocketAddress(3080);
socketChannel = socketChannel.bind(address);
/**检查套接字选项*/
Set<SocketOption<?>> socketOptions =
socketChannel.supportedOptions;
System.out.println(socketOptions.toString);
/**设置套接字的ToS(服务条款)选项*/
socketChannel.setOption(StandardSocketOption.IP_TOS, 3);
/**获取SO_KEEPALIVE 选项*/
Boolean keepAlive=
socketChannel.getOption(StandardSocketOption.SO_KEEPALIVE);
..
..
}
catch (IOException e)
{
System.out.println(e.getMessage);
}
此外,NetworkChannel
的出现使得多播操作成为可能。
2.6.2 MulticastChannel
像BitTorrent这样的对等网络程序一般都具备多播的功能。在Java的早期版本中,虽然拼凑一下也能实现多播,但却没有很好的API抽象层。Java 7中的新接口MulticastChannel
解决了这个问题。
术语多播(或组播)表示一对多的网络通讯,通常用来指代IP多播。其基本前提是将一个包发送到一个组播地址,然后网络对该包进行复制,分发给所有接收端(注册到组播地址中),如图2-5所示。
图2-5 多播示例
为了让新来的NetworkChannel
加入多播组,Java 7提供了一个新接口java.nio.channels.MulticastChannel
及其默认实现类DatagramChannel
。也就是说你可以很轻松地对多播组发送和接收数据。
下面的代码说明了如何加入IP地址为180.90.4.12的多播组,并对其发送和接收系统状态信息。
代码清单2-11 NetworkChannel
选项
try
{
/**选择网络接口*/
NetworkInterface networkInterface =
NetworkInterface.getByName("net1");
/**打开DatagramChannel*/
DatagramChannel dc =
DatagramChannel.open(StandardProtocolFamily.INET);
/**将通道设置为多播*/
dc.setOption(StandardSocketOption.SO_REUSEADDR,
true);
dc.bind(new InetSocketAddress(8080));
dc.setOption(StandardSocketOptions.IP_MULTICAST_IF,
networkInterface);
/**加入多播组*/
InetAddress group = InetAddress.getByName("180.90.4.12");
MembershipKey key = dc.join(group, networkInterface);
}
catch (IOException e)
{
System.out.println(e.getMessage);
}
到此为止,我们对NIO.2 API的初步研究已经结束了。希望你喜欢这次行色匆匆的旅程!