讀古今文學網 > Java程序員修煉之道 > 2.6 Socket和Channel的整合 >

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的初步研究已經結束了。希望你喜歡這次行色匆匆的旅程!