Java I/O全文摘要(五)數據源,網絡流

1. 網絡流

Java語言從一開始就考慮了網絡的設計。

它是第一個對網絡流支持和文件流支持同樣多(甚至更多)的語言。

但是具體的所使用的流往往隱藏在無文檔的sun包中。

因此,網絡流依賴於InputStream 和 OutputStream的主要方法。

當然,高層構建上,你可以對流加上 緩衝,加密,壓縮和其他一切你應用程序所需求的東西。


2 URLs

java.net.URL類代表了統一資源定位 (Uniform Resource Locator)

例如:http://www.cafeaulait.org/books/javaio2/

每個URL無歧義的代表了網絡上唯一的資源。

URL有六個構造函數,他們都可能拋出MalformedURLException。(MalformedURLException是IOException的子類

public URL(String url) throws MalformedURLException
public URL(String protocol, String host, String file)
 throws MalformedURLException
public URL(String protocol, String host, int port, String file)
 throws MalformedURLException
public URL(String protocol, String host, int port, String file,
  URLStreamHandler handler)  throws MalformedURLException
public URL(URL context, String url) throws MalformedURLException
public URL(URL context, String url, URLStreamHandler handler)
  throws MalformedURLException


如果參數沒有指定有效的URL,將拋出MalformedURLException異常。

僅僅帶有一個URL的構造體按照如下方式使用:

URL u = null;
try {
  u = new URL("http://www.poly.edu/schedule/fall2006/bgrad.html#cs");
}
catch (MalformedURLException ex) {
  // this shouldn't happen for a syntactically correct http URL
}

有時,你希望單獨指定協議,域名和API,按照下面的方式:

URL u = new URL("http", "www.poly.edu", "/schedule/ fall2006/bgrad.html#cs");

通常不需要指定端口,例如http默認端口爲80,但有時候端口號會改變,這時候,你需要使用帶有端口號的構造體:

URL u = new URL("http", "www.poly.edu", 80, "/schedule/ fall2006/bgrad.html#cs ");


此外,很多HTML包含了一個相關的URL,這也是最後兩個構造體的用法。

一旦URL建立,你就可以從中檢索數據了。


3.  從URL中獲得數據

可以使用openStream()從字節流中獲得原始數據,或者getContent( )返回代表數據的Java對象。

openStream()將構建一個與服務端連接的socket。

大多數網絡,包括局域網,速度也比文件要慢,也更不可信賴。

英特網就更慢了,所以你需要讀取少量數據,緩存到臨時的位置幷包裝它,這再後面的章節中,BufferedInputStream就是這麼幹的。


4. URL 連接

URL連接於URL緊緊相連,正如它名字一樣。

實際上,你可以通過URL的openConnection( )來獲得URLConnection。

很多時候,URL是URLConnection的唯一包裝類,

URLConnection提供了更多的客戶端服務端的會話,

它不僅可以從客戶端讀取從服務端發送過來的信息,也可以將信息從客戶端發往服務端。

java.net.URLConnection是一個抽象類,它可以處理不同類型的服務,例如FTP服務和WEB服務。

具體的子類隱藏在sun包中了,用於處理不同的服務。


5. 從URL Connections中讀取數據

URL連接分爲五部

(1)URL對象的建立

(2)使用URL對象的openConnection( )來創建URLConnection對象

(3)建立客戶端與服務端的連接參數和請求屬性

(4)使用連接方法connect( )來連接服務端,如果是網絡使用socket,本地連接則用文件流

(5)通過getInputStream( )獲得輸入流,或者通過getContent( )獲得內容句柄,也可通過getOutputStream( )向服務端發數據。


這個協議是基於HTTP 協議的,但是不是採用三次握手的方式,而是“單一請求,單一應答,關閉”的模式。

FTP可能不適用。

你無法直接構造URLConnection對象,你應該通過URL的 openConnection( )方法來獲得它。

getInputStream( )將返回從URL讀取數據的輸入流。

當然,如果連接無法打開(如遠端服務器不可達),connect( )將會拋出一個IOException

下面是使用URLConnection的一段代碼樣例.

    URL u = new URL(args[0]);
    URLConnection connection = u.openConnection( );
    in = connection.getInputStream( );
    for (int c = in.read(); c != -1; c = in.read( )) {
      System.out.write(c);
    }


6. 向URL Connections中寫入數據

與讀很相似,但是你必須確定你要這麼做。

使用通用的HTTP POST and PUT。

下面是步驟:

(1) 創建URL對象

(2)使用URL的openConnection( )方法來獲得URLConnection對象

(3) 向方法setDoOutput( )中傳入true表面你希望使用這個URLConnection對象來向服務器傳遞數據

(4) 如果你也希望讀取數據setDoInput(true)

(5) 創建你想要傳遞的數據,最好是字節數組byte array

(6) 調用getOutputStream( )來獲得輸出流,往裏面寫入第5步創建的數組

(7) 關閉輸出流

(8) 繼續使用getInputStream( )獲得輸入流做一些事情


7. Sockets

在數據從一個主機發往別處時,通常需要切割成數據報文。

數據報文的大小從幾十個字節到60000不等。

很多很大的東西都被切割成很小的部分,

這樣的好處是,一旦有內容丟失了,也只需要重傳丟失那部分的內容,

此外,如果到達不是順序的,也需要在接收端重新排列起來。


幸運的是,這些包對於Java程序而言是不可見的。

Java已經將其抽象成了socket,它提供可信賴的兩端之間的連接。

它獨立於內容的編碼,重傳丟失,亂序重排等細節。

socket執行4個基本操作:

1>連接遠端機器

2>發送數據

3>接收數據

4>關閉連接


一個socket可能連接超過一個遠端主機。

基本類:java.net.Socket

它提供了兩個主機間原始的,未翻譯的通訊。

沒有對於協議的抽象,那是URL和URLConnection關心的。

程序對於客戶端與服務器的通信有完全的責任。


爲了打開一個連接,構造一個Socket,然後制定要連接的host.

如果要連接一個新的主機,你需要創建一個新的Socket.

public Socket(String host, int port throws UnknownHostException, IOException
public Socket(InetAddress address, int port) throws IOException
public Socket(String host, int port, InetAddress localAddress, int localPort) throws IOException
public Socket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException

host參數可以是"www.oreilly.com" or "duke.poly.edu"

port端口號:大多數服務運行在知名的端口,如HTTP的80


8 Sockets數據

數據在Socket上的發送和接收是通過流的。

public InputStream  getInputStream( ) throws IOException
public OutputStream getOutputStream( ) throws IOException

它也有關閉方法。

public void close( ) throws IOException

9 服務端Socket

每個連接都有兩頭:客戶端,連接的發起者;服務端,連接的接受者。

爲了使得能夠建立連接,服務端必須寫有能夠讓其他主機進行連接的程序。

他們監聽來自遠端請求建立連接.


多個客戶端能夠同時連接到一個服務端。

服務端可通過端口來確定客戶端請求的服務。

由於需要同時處理多個連接請求,服務端需要多線程支持,輸入的請求入隊列,直到服務端能夠接受它們。

對於默認的情況下,隊列長度5~50,一旦滿了,再次入列的請求將被拒絕,直到有可用。


類:java.net.ServerSocket

它代表一個服務端Socket

public ServerSocket(int port) throws IOException
public ServerSocket(int port, int backlog) throws IOException
public ServerSocket(int port, int backlog, InetAddress bindAddr) throws IOException

通常,下面這樣就可以了:

ServerSocket ss = new ServerSocket(80);
如果端口已被綁定,拋出java.net.BindException


注意:在Unix 類系統上,端口必須在1~1023之間,否則accept()拋出BindException

0是特殊的情況,用於獲取可用端口。

你可以使用getLocalPort方法來獲取端口號

public int getLocalPort( )


客戶端可服務端有用於指定端口號的連接是很有意義的,這樣可以通過指定的端口號開闢新的連接用於獨立通信。

例如FTP服務使用兩個Socket,一個用於傳遞命令,一個用於傳遞數據。(先通過傳遞命令的將數據通道的基本參數傳給服務端)


一旦你已經有了ServerSocket,那麼調用accept( )方法來等待進入的連接。

這個方法被阻塞直到嘗試建立連接的出現,然後返回一個Socket對象。這個對象用於與客戶端通信。

public Socket accept( ) throws IOException


當然他也有close(),用於關閉

public void close( ) throws IOException


小Demo
ServerSocket ss = new ServerSocket(2345);
while (true) {
  Socket s = ss.accept( );
  OutputStream out = s.getOutputStream( );
  // send data to the client...
  s.close( );
}


注意關閉的是Socket,而不是ServerSocket。




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章