Java 編程中的聯網包括了定位和識別資源的能力以及通過 TCP 和 UDP 連接進行通信的能力。首先,您需要識別具有象 www.ibm.com 這樣名稱的資源,然後打開到該資源的連接,最後在您自己和連接的另一端之間發送信息包。由於安全性原因,可能會包括其它任務,但是整個過程是一樣的。對於 Java 平台,會在 java.net 包中找到支持這些操作的類。從 Java 編程的早期到現在,這些操作中大多數都未曾發生太大的變化。但是,隨著 Merlin 的發展,這些基本操作中有些已經作了改進,以支持有價值的新功能。在本文中,我們將研究五個此類功能:IPv6 支持、URI、網絡接口、非綁定套接字和安全套接字。
對 IPv6 地址的支持
首先讓我們研究一下對下一代因特網協議 V6(Internet Protocol V6,IPv6)尋址體系結構的新支持。借助於 InetAddress 的兩個新子類( Inet4Address 和 Inet6Address ),您能夠與基於 TCP 和 UDP 的應用程序進行連接。 Inet4Address 支持大多數機器所支持的較舊的(而且通常是唯一的)IP 尋址樣式,localhost 的格式為 127.0.0.1 。RFC2373(請參閱 參考資料)中所定義的新尋址方案提供了一種用冒號隔開的格式,其中 0:0:0:0:0:0:0:1 是與 127.0.0.1 等價的回送地址。新的類允許應用程序支持一種或這兩種尋址方案。
對 IPv6 的支持取決於底層平台是否支持它,Solaris 8 和更高版本,以及 Linux 2.1.2 和更高(RedHat 6.1+)版本都支持 IPv6,而 Microsoft Windows 並不支持它(Microsoft 的 Window 2000 實現是個有限的實現)。希望 J2SE 1.4 的 Windows 版本以後能支持 IPv6。
認識統一資源標識符
java.net 包現已包括了統一資源標識符(uniform resource identifier,URI)類。可將 URI 看作是幕後沒有協議處理程序的統一資源定位符(uniform resource locator,URL)。通常,URL 看上去象 http://www.ibm.com 。為了使 Java 語言運行時理解 URL,它需要知道該怎麼處理以 http: 開頭的信息。以前,如果您提出新協議(例如,象 jdbc:database ),那麼若沒有協議處理程序,則您不能將 jdbc:database 字符串作為 URL 處理。相反,您不得不嚴格地將它作為字符串處理,這正是 JDBC 現在所做的。
URI 的典型格式是: [scheme:][//authority][path][?query][#fragment] ,其中 authority 通常就是主機名。但是,它還可以包括用戶登錄信息和端口: [userInfo@]host[:port] 。URI 類自身提供了一系列的 getter 方法,以便了解 URI 各個特定的部分。在您先前傳遞看上去象 URL 的字符串(但這僅為了描述 URL 而非使用它)的地方,您應當使用該類。
用 NetworkInterface 列出網絡連接
您是否曾經想知道哪個聯網接口是可用的,但是在不回復到本機代碼的情況下又不知道該如何詢問呢?通常,連接至因特網的大多數機器中有兩個連接:到其自身的本地循環和到其本地服務供應商的連接。但是,有些機器是 多宿主的。它們有多個網卡,每個網卡都有一個到因特網的獨立連接並且都有自己的名稱和地址。有了這個新的 NetworkInterface 接口,您就可以在向外發送多點廣播數據報時指定使用哪個網卡,或查看網絡連接是否正常。清單 1 演示了該類的用法:
清單 1. 列出網絡接口
import java.net.*;
import java.util.Enumeration;
public class Nets {
public static void main(String args[]) throws SocketException {
Enumeration enum = NetworkInterface.getNetworkInterfaces();
while (enum.hasMoreElements()) {
NetworkInterface net = (NetworkInterface)enum.nextElement();
System.out.println(
"Names: " + net.getName() + " / " + net.getDisplayName());
Enumeration enum2 = net.getInetAddresses();
while (enum2.hasMoreElements()) {
InetAddress address = (InetAddress)enum2.nextElement();
System.out.println("\tAddress: " + address.getHostAddress());
}
}
}
}
您運行該程序所得的結果肯定是不同的。清單 2 包括了您想看到的輸出樣本:
清單 2. 清單 1 的樣本結果
Names: lo / MS TCP Loopback interface
Address: 127.0.0.1
Names: eth0 / 3Com EtherLink PCI
Address: 192.168.0.109
對未連接套接字和非綁定套接字的支持
通常,象在套接字之間進行讀寫之類的操作都是阻塞操作。在操作完成之前,調用線程都不能繼續運行。在 Merlin 新 I/O(NIO)類的幫助下,聯網類現在可以是非阻塞型的。無論哪一種情況(阻塞或非阻塞),新的 InetSocketAddress 和 SocketAddress 類都允許您打開到主機和端口的連接,然後在真正連接到主機之前為該連接設置一些選項。清單 3 顯示了基本的操作序列:
清單 3. 連接至主機和端口
String hostname = ...;
int port = ...;
SocketAddress socketAddress =
new InetSocketAddress(host, port);
SocketChannel channel = SocketChannel.open();
channel.configureBlocking(false);
channel.connect(socketAddress);
請在下個月的專欄文章中查閱有關 NIO 包的更多信息。
用安全套接字進行連接
Merlin 中有一個新的包: javax.net.ssl 。該包提供了使用 Java 安全套接字擴展(Java Secure socket extension,JSSE)的安全通信,該擴展更常用的名稱是 https URL 的安全套接字層(secure sockets layer,SSL)支持。您不再需要用標准擴展庫來實現 SSL 支持 - 它現已隨核心庫一起提供。通過請求來自 SSLSocketFactory 的 SSL 套接字,您自動地就獲得了一個安全連接(假設您所連接的服務器支持該功能)。獲取套接字後,您不必再執行任何特殊的操作了 - 它會完全象普通套接字那樣進行通信。
在清單 4 中,我們使用 SSL 來連接用戶指定的站點,或 Verisign,並獲取該站點的入口頁面。可以隨意將輸出保存到文件中,以便查看。
清單 4. 通過安全套接字進行連接
import java.io.*;
import java.net.*;
import javax.net.*;
import javax.net.ssl.*;
public class SslSample {
static final int HTTPS_PORT = 443;
public static void main(String args[]) throws IOException {
String hostname;
// If host not provided, connect to Verisign
if (args.length == 0) {
hostname = "www.verisign.com";
} else {
hostname = args[0];
}
// Get socket factory
SocketFactory factory = SSLSocketFactory.getDefault();
// Get socket from factory
Socket socket = factory.createSocket(hostname, HTTPS_PORT);
// Send request
OutputStream os = socket.getOutputStream();
PrintWriter pw = new PrintWriter(os);
// Setup command
String command = "GET / HTTP/1.0\r\n\r\n";
pw.print(command);
pw.flush();
// Get response
InputStream is = socket.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
pw.close();
br.close();
socket.close();
}
}
還有一個 HttpsURLConnection 類,可以象 jave.net.URLConnection 那樣使用它。
舊的類,新的技巧
並不是所有的聯網增強技術都是在新的類(和包)中實現的。許多現有的類也得到了增強。有些功能主要是在後台進行的,比如改進的 FTP 協議處理程序。現在,Merlin 的功能和 RFC1738 和 RFC959 的功能(請參閱 參考資料)匹配得更加緊密了,包括對被動方式的支持。另外, URLEncoder 和 URLDecoder 類都支持使用程序員指定的字符集進行編碼和解碼。HTTP 摘要認證支持也已經得到改進,並且 URLConnection 頭的處理已得到了增強,可以支持直接獲取和添加頭。
結束語
Merlin 給標准 Java 編程添加了許多功能。有些功能已經存在了一段時間了,但是現在才最終被合並進標准發行版。有些功能是新的,而其它的則被升級成現有的功能。隨著 Java 技術使用得越來越多,就越來越難跟上它不斷擴充的功能列表。有時候您需要沙裡淘金,但請堅持尋找 - 它們早就等在那了。