首页 » Java程序员修炼之道 » Java程序员修炼之道全文在线阅读

《Java程序员修炼之道》2.6 Socket和Channel的整合

关灯直达底部

应用软件对网络接入的需求比以往任何时候都要迫切。仿佛一夜之间,家里所有东西都要联网了。在旧版Java中,套接字和通道结合得并不是很好,将它们两个配合在一起是件棘手的事情。因此Java 7推出了NetworkChannel,把SocketChannel结合到一起,让开发人员可以轻松应对。

编写底层网络代码算是专业领域。如果你的工作领域与此无关,完全可以跳过这一节!但如果恰好你就是干这个的,你可以在本节对Java 7的新特性有一个初步了解。

我们先来看看套接字和通道在Javadoc中的定义,重温一下它们在Java中扮演的角色:

java.nio.channels包定义通道,表示连接到执行I/O操作的实体,比如文件和套接字。定义用于多路传输、非阻塞I/O操作的选择器。java.net.Socket类该类实现了客户端套接字(也称为“套接字”)。套接字是两个机器间通信的端点。

在旧版Java中,为了执行I/O操作,比如向TCP端口中写入数据,你需要将通道绑定到Socket的实现类上,但ChannelSocket彼此之间却有“代沟”:

  • 在旧版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的初步研究已经结束了。希望你喜欢这次行色匆匆的旅程!