標籤:協議棧 重用 異常 表示 alt 緩衝區 highlight 接收 操作
在Java NIO中用Channel來對程式與進行I/O操作主體的串連關係進行抽象,這些IO主體包括如檔案、Socket或其他裝置。簡而言之,指代了一種與IO操作對象間的串連關係。
按照Channel介面的定義,Channel只有open和closed兩種狀態,只有在channel處於open狀態下對其操作時才有效,而對closed的channel進行操作會導致拋出異常。相應的Channel介面也僅有isOpen()和close()兩種方法。
在Socket編程中,常用的Channel類是ServerSocketChannel和SocketChannel。ServerSocketChannel表示作為Socket服務端,處於監聽狀態的Socket串連。而SocketChannel表示一個已經建立的Socket串連。
ServerSocketChannel具有accept()方法,當該方法成功返回時,會返回一個已經建立的SocketChannle對象,這也表示了這兩種代表不同狀態的Socket Channel間的聯絡和區別。ServerSocketChannel通過bind()方法綁定到本地地址,並且可以通過setOption()方法設定SO_RCVBUF(Socket接收緩衝區大小)和SO_REUSEADDR(是否重用Socket地址,由於Socket在關閉時需要經過多個狀態的變遷,這個選項通常在需要快速重啟的情境下有用)兩個Socket選項。
SocketChannel採用connet()方法建立串連,並且支援非阻塞式建立,在非阻塞狀態下串連的最終建立狀態通過isConnetionPending()和finishConnect()進行組合判斷。SocketChannel同時支援非同步關閉,若寫線程主動關閉了Channel,則並發的讀操作將讀取不到內容;若讀線程主動關閉了Channel,則並發的寫操作將得到AsynchronousCloseException。同樣的對SocketChannle可以通過setOption()方法設定若干選項,包括:SO_SNDBUF(發送緩衝區), SO_RCVBUF, SO_KEEPALIVE(是否採用協議棧實現的保活機制,預設為FALSE), SO_REUSEADDR, SO_LINGER(阻塞式串連下的關閉等待時間長度), TCP_NODELAY(是否禁用Nagle演算法)。
這兩個類涉及的相關類圖如所示:
可見,ServerSocketChannel和SocketChannel均繼承了SelectableChannel以支援與Selector配合實現非阻塞式IO。SocketChannel繼承了若干支援讀寫操作的Channel以支援讀寫操作。
另外,Channel的讀寫需要藉助於Buffer,可見在NIO中Buffer是程式中其他對象與Channel互動的中介,通過Buffer和Channel的配合實現對I/O對象的讀寫操作。
幾個關鍵的介面定義如下
public interface Channel {/** * 判斷是否開啟 * @return */public boolean isOpen();public void close() throws IOException;}/** * 可中斷Channel</p> * 1. 可被非同步關閉. 若當前線程阻塞於Channel的讀寫操作,</l> * 當另一線程調用close操作後,當前線程會收到一個AsynchronousCloseException</p> * * 2. 可中斷. 若當前線程阻塞於Channel,當其他線程觸發interrupt方法時</l> * 會導致Channel Close,當前線程收到一個ClosedByInterruptException, * 其interrupt狀態被設定</p> * * 3. 若當前線程interrupt狀態已被設定,當調用當前Channel的阻塞IO操作時,</l> * channel會被close,線程會收到ClosedByInterruptException. </l> * 其interrupt狀態保持不變.</p> * * @author luojiahu * */public interface InterruptibleChannel extends Channel{public void close() throws IOException;}/** * 可讀Byte Channel * 可對當前Channel阻塞讀. 若有其他線程正對當前Channel進行讀操作,</l> * 調用read會一直阻塞至其他上一讀操作完成。 * * @author luojiahu * */public interface ReadableByteChannel extends Channel {/** * 從當前Channel中讀取內容寫入Buffer</l> * 是否能夠讀入內容,取決於當前Channel的狀態.</l> * 如,對於一個非阻塞的Socket Channel,如果當前socket的</l> * 接收緩衝區沒有任何內容,則不能寫入任何內容到src * @param src * @return * @throws IOException */public int read(ByteBuffer src) throws IOException;}/** * 可寫Byte Channel * 可對當前Channel阻塞寫.</l> * @author luojiahu * */public interface WritableByteChannel extends Channel {/** * 從dst buffer中讀取內容寫入當前Channel</l> * 是否能夠寫入內容取決於當前Channel的狀態</l> * 如對於非阻塞 Socket Channel,只能寫入不大於</l> * 對應寫入緩衝區可寫大小的內容 * * @param dst * @throws IOException */public void write(ByteBuffer dst) throws IOException;}/** * 網路socket channel</l> * @author luojiahu * */public interface NetWorkChannel extends Channel{/** * 綁定到本地地址</l> * 一旦綁定,則綁定直至通道關閉</l> * 如果參數未空,則綁定至自動分配的地址 * @param local * @return * @throws IOException */NetWorkChannel bind(SocketAddress local) throws IOException;/** * 擷取綁定的本地地址 * @return * @throws IOException */SocketAddress getLocalAddress() throws IOException;/** * 設定socket 選項 * @param name * @param value * @return * @throws IOException */<T> NetworkChannel setOption(SocketOption<T> name, T value) throws IOException;}
Java NIO 之 Socket Channel