應用軟件對網絡接入的需求比以往任何時候都要迫切。彷彿一夜之間,家裡所有東西都要聯網了。在舊版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的初步研究已經結束了。希望你喜歡這次行色匆匆的旅程!