您的位置:首頁>熱點推薦 >

              Java 網絡編程 —— 非阻塞式編程

              2023-05-14 16:25:03    來源:博客園
              線程阻塞概述

              在生活中,最常見的阻塞現象是公路上汽車的堵塞。汽車在公路上快速行駛,如果前方交通受阻,就只好停下來等待,等到公路順暢,才能恢復行駛。


              【資料圖】

              線程在運行中也會因為某些原因而阻塞。所有處于阻塞狀態的線程的共同特征:放棄 CPU,暫停運行,只有等到導致阻塞的原因消除,才能恢復運行,或者被其他線程中斷該線程會退出阻塞狀態,并且拋出 InterruptedException

              導致線程阻塞的原因主要有以下方面:

              線程執行了 Threadsleep(int n)方法,線程放棄 CPU,睡眠 n ms,然后恢復運行線程要執行一段同步代碼,由于無法獲得相關的同步鎖,只好進入阻塞狀態,等到獲取同步鎖再恢復運行線程執行了一個對象的 wait()方法,進入阻塞狀態,只有等到其他線程執行了該對象的 notify()notifyAll()方法,才可能將其喚醒線程執行 IO 操作或進行遠程通信時,會因為等待相關的資源而進入阻塞狀態

              進行遠程通信時,在客戶程序中,線程在以下情況下可能進入阻塞狀態:

              請求與服務器建立連接時,即當線程執行 Socket 的帶參數的構造方法,或執行 Socke 的 connect()方法時,會進入阻塞狀態,直到連接成功,此線程才從 Socket 的構造方法或 connect()方法返回

              線程從 Socket 的輸入流讀入數據時,如果沒有足夠的數據,就會進入阻塞狀態,直到讀到了足夠的數據,或者到達輸入流的末尾,或者出現了異常,才從輸入流的 read()方法返回或異常中斷

              輸入流中有多少數據才算足夠呢?這要看線程執行的 read()方法的類:

              int read():只要輸入流中有 1 字節,就算足夠int read(byte[] buf):只要輸入流中的字節數目與參數 buff 數組的長度相同,就算足夠String readLine():只要輸入流中有 1 行字符,就算足夠

              線程向 Socket 的輸出流寫一批數據時,可能會進入阻塞狀態,等到輸出了所有的數據,或者出現異常,才從輸出流的 write()方法返回或異常中斷

              如果調用 Socket 的 setSoLinger()方法設置了關閉 Socket 的延遲時間,那么當線程執行 Socket 的 close()方法時,會進入阻塞狀態,直到底層 Socket 發送完所有剩余數據或者超過了 setSoLinger()方法設置的延遲時間,才從 close()方法返回

              在服務器程序中,線程在以下情況下可能會進入阻塞狀態:

              線程執行 ServerSocket 的 accept()方法,等待客戶的連接,直到接收到了客戶連接才從 accept()方法返回線程從 Socket 的輸入流讀入數據時,如果輸入流沒有足夠的數據就會進入阻塞狀態線程向 Socket 的輸出流寫一批數據時,可能會進入阻塞狀態,等到輸出了所有的數據,或者出現異常,才從輸出流的 write()方法返回或異常中斷

              由此可見,無論是在服務器程序還是客戶程序中,當通過 Socket 的輸入流和輸出流讀寫數據時,都可能進入阻塞狀態。這種可能出現阻塞的輸入和輸出操作被稱為阻塞 IO。與此對照,如果執行輸入和輸出操作時,不會發生阻塞,則稱為非阻塞 IO

              非阻塞通信的基本思想

              假如同時要做兩件事:燒開水和煮粥

              燒開水的步驟如下:

              鍋子里放水,打開煤氣爐等待水燒開 // 阻塞關閉煤氣爐,把開水灌到水壺里

              煮粥的步驟如下:

              鍋子里放水和米,打開煤氣爐等待粥煮開 // 阻塞調整煤氣爐,改為小火等待粥煮熟 // 阻塞關閉煤氣爐

              為了同時完成兩件事,一種方案是同時請兩個人分別做其中的一件事,這相當于采用多線程來同時完成多個任務。還有一種方案是讓一個人同時完成兩件事,這個人應該善于利用一件事的空閑時間去做另一件事,這個人一刻也不應該閑著:

              鍋子里放水,打開煤氣爐 // 開始燒開水鍋子里放水和米,打開煤氣爐 // 開始煮粥while(一直等待,直到有水燒開、粥煮開或粥煮熟事件發生) { // 阻塞if(水燒開)關閉煤氣爐,把開水灌到水壺里;if((粥煮開)調整煤氣爐,改為小火;if(粥熟)關閉煤氣爐;}

              這個人不斷監控燒水和煮粥的狀態,如果發生了條件中任一事件就去處理,處理完一件事后繼續監控,直到所有的任務都完成

              以上工作方式也可以被運用到服務器程序中,服務器程序只需要一個線程就能同時接收客戶的連接、接收各個客戶發送的數據,以及向各個客戶發送響應數據。服務器程序的處理流程如下:

              while(一直等待,直到有接收連接就緒事件、讀緒事件或寫就緒事件發生) { //阻塞if(有客戶連接)接收客戶的連接; // 非阻塞if(某個socket的輸入流中有可讀數據)從輸入流中讀數據; // 非阻塞if(某個socket的輸出流可以寫數據)向輸出流寫數據; // 非阻塞}

              以上處理流程采用了輪詢的工作方式,當某一種操作就緒,就執行該操作,否則就查看是否還有其他就緒的操作可以執行。線程不會因為某一個操作還沒有就緒,就進入阻塞狀態,一直傻傻地在那里等待這個操作就緒

              為了使輪詢的工作方式順利進行,接收客戶的連接、從輸入流讀數據,以及向輸出流寫數據的操作都應該以非阻寒的方式運行。所謂非阻塞,指當線程執行這些方法時,如果操作還沒有就緒,就立即返回,而不會一直等到操作就緒

              非阻塞通信 API

              java.nio.channels包提供了支持非阻塞通信的類,如下所述:

              ServerSocketChannelServerSocket的替代類,支持阻塞通信與非阻塞通信SocketChannelSocket的替代類,支持阻塞通信與非阻塞通信Selector:為 ServerSocketChannel監控接收連接就緒事件,為 SocketChannel監控連接就緒、讀就緒和寫就緒事件SelectionKey:代表 ServerSocketChannel以及 SocketChannelSelector注冊事件的句柄。當一個 SelectionKey對象位于 Selector對象的 selected-keys集合中,就表示與這個 SelectionKey對象相關的事件發生了

              ServerSocketChannelSocketChannel都是 SelectableChannel的子類,如圖所示,SelectableChannel類及其子類都能委托 Selector來監控它們可能發生的一些事件,這種委托過程也被稱為注冊事件過程

              ServerSocketChannelSelector注冊接收連接就緒事件的代碼如下:

              SelectionKey key = serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

              SelectionKey類的一些靜態常量表示事件類型,ServerSockerChamnel只可能發生一種事件:

              SelectionKey.OP_ACCEPT:接收連接緒事件,表示至少有了一個客戶連接,服務器可以接收這個連接、

              SocketChannel可能發生以下三種事件:

              SelectionKey.OP_CONNECT:連接就緒事件,表示客戶與服務器的連接已經建立成功SelectionKey.OP_READ:讀就緒事件,表示輸入流中已經有了可讀數據,可以執行讀操作了SelectionKey.OP_WRITE: 寫就緒事件,表示已經可以向輸出流寫數據了

              SocketChannel提供了接收和發送數據的方法:

              read(ByteBuffer buffer):接收數據,把它們存放到參數指定的 ByteBufferwrite(ByteBuffer buffer):把參數指定的 ByteBuffer 中的數據發送出去

              ByteBuffer表示字節緩沖區,SocketChannelread()write()方法都會操縱 ByteBufferByteBuffer類繼承于 Buffer類。ByteBuffer中存放的是字節,為了把它們轉換為字符串還需要用到 Charset類,Charset類代表字符編碼,它提供了把字節流轉換為字符串(解碼過程)和把字符串轉換為字節流(編碼過程)的實用方法

              下面分別介紹 BufferCharsetSelectableChannelServerSocketChannelSocketChannelSelectorSelectionKey的用法

              緩沖區 Buffer

              數據輸入和輸出往往是比較耗時的操作,緩沖區從兩個方面提高 I/O 操作的效率:

              減少實際的物理讀寫次數緩沖區在創建時被分配內存,這塊內存區域一直被重用,這可以減少動態分配和回收內存區域的次數

              java.nio包公開了 Buffer類的 API,使得 Java 程序可以直接控制和運用緩沖區,所有的緩沖區都有以下屬性:

              容量(capacity):表示緩沖區可以保存多少數據極限(limit):表示緩沖區的當前終點,不能對緩沖區中超過極限的區域進行讀寫操作位置(position):表示緩沖區中下一個讀寫單元的位置

              以上三個屬性的關系為:容量 > 極限 >= 位置 >= 0

              緩沖區提供了用于改變以上三個屬性的方法:

              // 把極限設為容量,把位置設為0clear();// 把極限設為位置,把位置設為 0flip();// 不改變極限,把位置設為0rewind();

              Buffer類的 remaining()方法返回緩沖區的剩余容量,取值等于 極限 - 位置

              Buffer類的 compact()方法刪除緩沖區內從 0 到當前位置 position 的內容,然后把從當前位置 position 到極限limit 的內容拷貝到 0 到 limit - position 的區域內

              java.nio.Buffer類是一個抽象類,不能被實例化。它共有 8 個具體的緩沖區類,其中最基本的緩沖區是 ByteBuffer,它存放的數據單元是字節,ByteBufer類并沒有提供公開的構造方法,但是提供了兩個獲得 ByteBuffer實例的靜態工廠方法:

              // 返回一個ByteBuffer對象,參數capacity指定緩沖區的容量allocate(int capacity);// 返回一個ByteBuffer對象,參數capacity指定緩沖區的容量// 該方法返回的緩沖區被稱為直接緩沖區,能進一步提高 I/O 操作的速度// 分配直接緩沖區的系統開銷很大,因此只有在緩沖區較大并且長期存在,或經常重用時,才使用該緩沖區directAllocate(int capacity);

              除 boolean 類型以外,每種基本類型都有對應的緩沖區類,包括 CharBufferDoubleBufferFloatBufferIntBufferLongBufferShortBuffer。在 CharBuffer中存放的數據單元為字符,以此類推。還有一種緩沖區是 MappedByteBuffer,它是 ByteBuffer的子類,能夠把緩沖區和文件的某個區域直接映射

              所有具體緩沖區類都提供了讀寫緩沖區的方法:

              // 相對讀,從緩沖區的當前位置讀取一個單元的數據,讀完后把位置加1get();// 絕對讀,從參數 index 指定的位置讀取一個單元的數據get(int index);// 相對寫,向緩沖區的當前位置寫一個單元的數據,寫完后把位置加1put(單元數據類型 data);// 絕對寫,向參數index指定的位置寫入一個單元的數據put(int index, 單元數據類型 data);

              ByteBuffer類不僅可以讀取和寫入一個單元的字節,還可以讀取和寫入 int、char、float 和 double 等基本類型的數據,例如:

              getInt()getInt(int index)

              以上不帶 index 參數的方法會在當前位置讀取或寫入數據,稱為相對讀寫。帶 index 參數的方法會在 index 參數指定的位置讀取或寫入數據,稱為絕對讀寫

              字符編碼 Charset

              java.nio.Charset類的每個實例代表特定的字符編碼類型,把字節序列轉換為字符串的過程稱為解碼,把字符串轉換為字節序列的過程稱為編碼

              Charset類提供了編碼與解碼的方法:

              // 對參數str指定的字符串進行編碼,把得到的字節序列存放在一個ByteBuffer對象并將其返回ByteBuffer encode(String str);// 對參數cb指定的字符緩沖區中的字符進行編碼,把得到的字節序列存放在一個ByteBuffer對象并將其返回ByteBuffer encode(CharBuffer cb);// 對參數bb指定的ByteBuffer的字節序列進行解碼,把得到的字符序列存放在一個CharBuffer對象并將其返回CharBuffer decode(ByteBuffer bb);

              Charset類的靜態 forName(String encode)方法返回一個 Charset對象,參數 encode指定編碼類型。例如以下代碼創建了一個代表 GBK 編碼的 Charset對象

              Charset charset = Charset.forName("GBK");

              Charset類還有一個靜態方法 defaultCharset(),它返回代表本地平臺的默認字符編碼的 Charset對象

              通道 Channel

              通道(Channel)用來連接緩沖區與數據源或數據匯(即數據目的地),數據源的數據經過通道到達緩沖區,緩沖區的數據經過通道到達數據匯

              Channel 的主要層次結構如下:

              java.nio.channels.Channel接口只聲明了兩個方法:

              // 關閉通道close();// 判斷通道是否打開isOpen();

              Channel接口的兩個最重要的子接口是 ReadableByteChannelWritableByteChannelReadableByteChannel接口聲明了 read(ByteBuffer dst)方法,該方法把數據源的數據讀入參數指定的 ByteBuffer緩沖區中。WritableByteChannel接口聲明了 write(ByteBuffer src)方法,該方法把參數指定的 ByteBuffer緩沖區中的數據寫到數據匯中

              ByteChannel接口是一個便利接口,它擴展了 ReadableByteChannelWritableByteChannel接口,因而同時支持讀寫操作

              ScatteringByteChannel接口擴展了 ReadableByteChannel接口,允許分散地讀取數據。分散讀取數據指單個讀取操作能填充多個緩沖區,ScatteringByteChannel接口聲明了 read(ByteBuffer[] dsts)方法,該方法把從數據源讀取的數據依次填充到參數指定的各個 ByteBuffer

              GatheringByteChannel擴展了 WritableByteChannel接口,允許集中地寫入數據。集中寫入數據指單個寫操作能把多個緩沖區的數據寫到數據, GatheringByteChannel接口聲明了 write(ByteBuffer[] srcs)方法,該方法依次把參數指定的每個 ByteBuffer中的數寫到數據匯

              FileChannel類是 Channel接口的實現類,代表一個與文件相連的通道。該類實現了 ByteChannelScatteringByteChannelGatheringByteChannel接口,支持讀操作、寫操作、分散讀操作和集中寫操作。FileChannel類沒有提供公開的構造方法,因此不能用 new語句來構造它的實例。不過,在FileInputStreamFileOutputStreamRandomAccessFile類中提供了 getChannel()方法,該方法返回相應的 FileChannel對象

              SelectableChannel也是一種通道,它不僅支持阻塞的 I/O操作,還支持非阻塞的 I/OSelectableChannel有兩個子類,ServerSocketChannelSocketChannelSocketChannel還實現了 ByteChannel接口,具有 read(ByteBuffer dst)write(ByteBuffer src)方法

              1. SelectableChannel 類

              SelectableChannel是一種支持阻塞 IO 和非阻塞 IO 的通道。在非阻塞模式下,讀寫數據不會阻塞,并且 SelectableChannel可以向 Selector注冊讀就緒和寫就緒等事件。Selector負責監控這些事件,等到事件發生時,比如發生了讀就緒事件,SelectableChannel就可以執行讀操作了

              SelectableChannel的主要方法如下:

              // 當參數block為true,表示把SelectableChannel設為阻塞模式// 當參數block為false時,表示把SelectableChannel設為非阻塞模式// SelectableChannel默認采用阻塞模式// 該方法返回SelectableChannel對象本身的引用,相當于return thispublic SelectableChannel configureBlocking(boolean block) throws IOException// 以下兩個方法都向Selector注冊事件public SelectionKey register(Selector sel,int ops) throws ClosedChannelExceptionpublic SelectionKey register(Selector sel,int ops,Object attachment) throws ClosedChannelException

              以下是 socketChannelSelector注冊讀就緒和寫就緒事件

              SelectionKey key = socketChannel.register(selector.SelectionKey.OP_READ | SelectionKey.OP_WRITE);

              register()方法返回一個 SelectionKey對象,SeletionKey被用來跟蹤被注冊的事件。第二個 register()方法還有一個 Object類型的參數 attachment,用于為 SelectionKey關聯附件,當被注冊事件發生后,需要處理該事件時,可以從 SelectionKey中獲得這個附件,該附件可用來包含與處理這個事件相關的信息

              2. ServerSocketChannel 類

              ServerSocketChannel繼承自 SelectableChannel,是 ServerSocket的替代類,通過它的靜態方法 open()來創建。每個 ServerSockeChannel對象都與一個 ServerSocket對象關,通過 socket()方法返回與它關聯的 ServerSocket對象。可通過以下方式把服務器進程綁定到一個本地端口:

              serverSocketChannel.socket().bind(port);

              ServerSocketChannel的主要方法如下:

              // 返回一個ServerSocketChannel對象,該對象沒有與任何本地端口綁定,并且處于阻塞模式public static ServerSocketChannel open() throws IOException// 用于接收客戶的連接,如果處于非阻塞狀態,當沒有客戶連接時就立即返回nullpublic SocketChannel accept() throws IOException// 返回ServerSocketChannel所能產生的事件,這個方法總是返回SelectionKey.OP_ACCEPTpublic final int validOps()// 返回ServerSocketChannel關聯的ServerSocket對象public ServerSocket socket()
              3. SocketChannel類

              SockeChannel可以被看作是 Socket的替代類,SockeChannel不僅繼承了 SelectableChannel,而且實現了 ByteChannelSockeChannel同樣通過它的靜態方法 open()來創建

              public static SocketChannel open() throws IOException// 帶參數的構造方法還會建立與遠程服務器的連接public static SocketChannel open(SocketAddress remote) throws IOException

              SocketChannel的主要方法如下:

              // 返回ServerSocketChannel所能產生的事件,這個方法總是返回以下值// SelectionKey.OP_CONNECT | SelectionKey.OP_READ | SelectionKey.OP_WRITEpublic final int validOps()// 返回SocketChannel關聯的Socket對象public Socket socket()// 建立遠程連接,當處于非阻塞模式時,如果立即連接成功返回true,否則返回falsepublic boolean connect(SocketAddress remote) throws IOException// 判斷底層Socket是否已經建立遠程連接public boolean isConnected()// 判斷是否正在進行遠程連接,如果遠程連接操作已經開始,但還沒有完成,則返回true,否則返回false// 也就是說,無論底層Socket還沒有開始連接,或者已經連接成功,該方法都會返回falsepublic boolean isConnectionPending()// 試圖完成連接遠程服務器的操作// 非阻塞模式下,建立連接從調用connect()方法開始,到調用finishConnect()方法結束// 如果在調用此方法之前連接已經建立,則立即返回true,否則立即返回false// 阻塞模式下,如果連接操作還沒有完成,則會進入阻塞狀態,直到連接完成,或者出現IO異常public boolean finishConnect) throws IOException// 從Channel讀入若干字節,存放到參數指定的ByteBuffer// 假設ByteBuffer剩余容量為r,阻塞模式下,該方法會爭取讀到r字節// 如果輸入流中不足r字節,就進入阻塞狀態,直到讀入了r字節,或者讀到了輸入流末尾,或者出現了IO異常// 非阻塞模式下,該方法奉行能讀到多少數據就讀多少數據的原則// 通道中的可讀數據,有可能不足r字節,或者為0字節,總是立即返回// 該方法返回實際上讀入的字節數,有可能為0,如果返回-1,表示讀到了輸入流的末尾public int read(ByteBuffer dst) throws IOException// 把參數src指定的ByteBuffer的字節寫到Channel// 假設ByteBuffer剩余容量為r,阻塞模式下,該方法會爭取輸出r字節// 如果底層網絡的輸出緩沖區不能容納r字節,就進入阻塞狀態,直到輸出了r字節,或者出現了IO異常// 非阻塞模式下,該方法奉行能輸出多少數據就輸出多少數據的原則,有可能不足r字節,或者為0字節,總是立即返回// 該方法返回實際上輸出的字節,有可能為0public int write(ByteBuffer src) throws IOException
              Selector 類

              只要 ServerSockerChannel以及 SocketChannelSelector注冊了特定的事件,Selector就會監控這些事件是否發生。SelectableChannelregister()方法負責注冊事件,該方法返回 SelectionKey對象,該對象是用于跟蹤這些被注冊事件的句柄

              Selector對象中會包含三種類型的 SelectionKey的集合:

              all-keys:當前所有向 Selector注冊的 SelectionKey的集合,Selectorkeys()方法返回該集合selected-keys:相關事件已經被 Selector捕獲的 SelectionKey的集合,SelectorselectedKeys()方法返回該集合cancelled-keys:已經被取消的 SelectionKey的集合,Selector沒有提供訪問這種集合的方法

              當執行 SelectableChannelregiste()方法,會新建一個 SelectionKey并加入 Selectorall-keys集合中。如果關閉了與 SelectionKey對象關聯的 Channel對象,或者調用了 SelectionKey對象的 cancel()方法,那么這個 SelectionKey對象就會被加入 cancelled-keys集合,表示已經被取消,在程序下一次執行 Selectorselect()方法時,被取消的 SelectionKey對象將從所有的集合(包括 all-keys集合、selected-keys集合和 cancelled-keys集合)中被刪除

              在執行 Selectorselect()方法時,如果與 SelectionKey相關的事件發生了,這個 SelectionKey就被加入 selected-keys集合中。程序直接調用 selected-keys集合的 remove()方法,或者調用它的 Iteratorremove()方法,都可以從 selected-keys集合中刪除一個 SelectionKey對象

              程序不允許直接通過集合接口的 remove()方法刪除 all-keys集合中的 SelectionKey對象,這會導致 UnsupportedOperationException

              Selector類的主要方法如下:

              // Selector的靜態工廠方法,創建一個Selector對象public static Selector open() throws IOException// 判斷Selector是否處于打開狀態,Selector對象創建后就處于打開狀態,當調用close()方法就進入關閉狀態public boolean isOpen()// 返回Seleclor的all-keys集合,包含了所有與Seclector關聯的SelectionKey對象public Set keys()// 返回相關事件已經發生的SelectionKey對象的數目// 該方法采用非阻塞的工作方式,返回當前相關事件已經發生的SelectionKey對象的數目,如果沒有,就立即返回0public int selectNow() throws IOException// 返回相關事件已經發生的SelectionKey對象的數目// 該方法采用阻塞的工作方式,如果一個也沒有,就進入阻塞狀態,直到出現以下情況之一,就會從select()返回:// 1.至少有一個SelectionKey的相關事件已經發生// 2.其他線程調用了Selector的wakeup()方法// 3.當前執行select()方法的線程被其他線程中斷// 4.超出了等待時間public int select() throws IOExceptionpublic int select(long timeout) throws IOException// 喚醒執行Selector的select()方法 public Selector wakeup()// 關閉 Selector// 如果有其他線程正執行這個Selector的select()方法并且處于阻塞狀態,這個線程會立即返回// close()方法使得Selector占用的所有資源都被釋敗,所有關聯的SelectionKey都被取消public void close() throws IOException
              SelectionKey 類

              SelectionKey中定義了四種事件,分別用四個 int 類型的常量來表示:

              SelectionKey.OP_ACCEPT:接收連接就緒事件,表示服務器監聽到了客戶連接,服務器可以接收這個連接了,常量值為 16SeiectionKey.OP_CONNECT:連接就緒事件表示客戶與服務器的連接已經建立成功,常量值為 8SelectionKey.OP_READ:讀就緒事件,表示通道中已經有了可讀數據,可以執行讀操作了,常量值為 1SelectionKey.OP_WRITE:寫就緒事件表示已經可以向通道寫數據了,常量值為 4

              以上常量分別占據不同的二進制位,因此可以通過二進制的或運算來將它們進行任意組合

              一個 SelectionKey對象中包含兩種類型的事件:

              所有感興趣的事件:通過 SelectableChannelregister()方法注冊事件時,可以在參數中指定 SelectionKey感興趣的事件

              SelectionKey key = socketChannel.register(selector,SelectionKey.OP_CONNECT | SelectionKey.OP_READ);

              該代碼表示這個 SelectionKey對讀就緒和寫就緒事件感興趣,與之關聯的 Selector對象會負責監控這些事件

              SelectionKey的帶參數的 interestOps(int ops)方法也可以為 SelectionKey對象增加一個感興趣的事件,如下代碼所示:

              key.interestOps(SelectionKey.OP_WRITE);

              所有已經發生的事件:SeletionKeyreadyOps()方法返回所有已經發生的事件,例如假定返回值為 SelectionKey.OP_WRITE | SelectionKey.OP_READ,表示讀就緒和寫就緒事件已經發生了,這意味著與之關聯的 SocketChannel對象可以進行讀操作和寫操作了

              SelectionKey的主要方法如下:

              // 返回與這個SelectionKey對象關聯的SelectableChannel對象public SelectableChannel channel()// 返回與這個SelectionKey對象關聯的Selector對象public Selector selector()// 判斷這個SelectionKey是否有效// 當SelectionKey對象創建后,它就一直處于有效狀態// 如果調用了它的cancel()方法,或關閉了與它關聯的SelectableChannel或Selector對象,它就失效public boolean isValid()// 使SelectionKey對象失效public void cancel()// 返回這個SelectionKey感興趣的事件public int interestOps()// 為SelectionKey增加感興趣的事件public SelectionKey interestOps(int ops)// 返回已經就緒的事件public int readyOps()// 判斯與之關聯的SocketChannel的讀就緒事件是否已經發生public final boolean isReadable()// 判斷與之關聯的SocketChannel的寫就緒事件是否已經發生public final boolean isWritable()// 判斷與之關聯的SocketChannel的連接就緒事件是否已經發生public final boolean isConnectable()// 判斷與之關聯的ServerSocketChannel的接收連接就緒事件是否已經發生public final boolean isAcceptable()// 使SelectionKey關聯一個附件,一個SelectionKey對象只能關聯一個Object類型的附件// 如果多次調用該方法,則只有最后一個附件與SelectionKey對象關聯public final Object attach(Object obj)// 返回與SelectionKey對象關聯的附件public final Object attachment()
              Channels 類

              Channels類是一個簡單的工具類,提供了通道與傳統的基于 IO 的流、ReaderWriter之間進行轉換的靜態方法

              ReadableByteChannel newChannel(InputStream in) // 輸入流轉換成讀通道WritableByteChannel newChannel(OutputStream out) // 輸出流轉換成寫通道InputStream newInputStream(AsynchronousByteChannel ch) // 異步通道轉換成輸入流InputStream newInputStream(ReadableByteChannel ch) // 讀通道轉換成輸入流OutputStream newOutputStream(AsynchronousByteChannel ch) // 異步通道轉換成輸出流OutputStream newOutputStream(WritableByteChannel ch) // 寫通道轉換成輸出流Reader newReader(ReadableByteChannel ch,String csName) // 讀通道轉換成Reader,參數csName指定字符編碼Reader newReader(ReadableByteChannel ch,Charset charset)//讀通道轉換成Reader.參數charset指定字符編碼Reader newReader(ReadableByteChannel ch,CharsetDecoder dec, int minBufferCap) // 讀通道轉換成 Reader,參數dec指定字符解碼器,參數minBufferCap指定內部字節緩沖區的最小容量Writer newWriter(WritableByeChannel ch, String csName) // 寫通道轉換Writer.參數csName指定字符編碼Writer newWriter(WritableByeChannel ch, Charset charset) // / 寫通道轉換Writer.參數charset指定字符編碼Writer newWriter(WritableByeChannel ch, CharsetEncoder enc, int minBufferCap) // 寫通道轉換成Writer,參數dec指定字符解碼器,參數minBufferCap指定內部字節緩沖區的最小容量
              Socket 選項

              從 JDK7 開始,SocketChannelServerSocketChannelAsynchronousSocketChannelAsynchronousServerSocketChannelDatagramChannel都實現了新的 NetworkChannel接口。NetworkChannel接口的主要作用是設置和讀取各種 Socket 選項

              NetworkChannel接口提供了用于設置和讀取這些選項的方法:

               T getOption(SocketOption name) // 獲取特定的Socket選項值 NetworkChannel setOption(SocketOption name, T value) // 設置特定的Socket選項Set> supportedOptions() // 獲取所有支持的Socket選項

              SocketOptionl類是一個泛型類,SocketOption中的 T代表特定選項的取值類型,可選值包括 IntegerBooleanNetworkInterface

              StandardSocketOptions類提供了以下表示特定選項的常量:

              SocketOption  --  StandardSocketOptions.IP_MULTICAST_IFSocketOption  --  StandardSocketOptions.IP_MULTICAST_LOOPSocketOption  --  StandardSocketOptions.IP_MULTICAST_TTLSocketOption  --  StandardSocketOptions.IP_TOSSocketOption  --  StandardSocketOptions.SO_BROADCASTSocketOption  --  StandardSocketOptions.SO_KEEPALIVESocketOption  --  StandardSocketOptions.SO_LINGERSocketOption  --  StandardSocketOptions.SO_RCVBUFSocketOption  --  StandardSocketOptions.SO_REUSEADDRSocketOption  --  StandardSocketOptions.SO_REUSEPORTSocketOption  --  StandardSocketOptions.SO_SNDBUFSocketOption  --  StandardSocketOptions.TCP_NODELAY

              關鍵詞:

              相關閱讀

              在线看亚洲十八禁网站| 337p日本欧洲亚洲大胆精品555588| 亚洲avav天堂av在线网毛片| 亚洲婷婷国产精品电影人久久| 亚洲成A∨人片在线观看无码| 成人精品国产亚洲欧洲| 亚洲熟妇自偷自拍另欧美| 亚洲VA中文字幕无码毛片| 亚洲综合成人婷婷五月网址| 久久久久亚洲Av片无码v| 亚洲第一成年免费网站| 亚洲成色999久久网站| 亚洲女同成人AⅤ人片在线观看| 77777_亚洲午夜久久多人| 亚洲国产国产综合一区首页| 亚洲A∨无码无在线观看| 亚洲国产综合精品中文第一区| 亚洲AV日韩AV天堂一区二区三区| 久久久久亚洲AV成人无码 | 亚洲午夜久久久久久久久久| 亚洲日韩国产AV无码无码精品| 亚洲黄色三级网站| 亚洲码在线中文在线观看| 亚洲人成影院在线无码按摩店| 亚洲午夜国产精品无码老牛影视| 亚洲老妈激情一区二区三区| 亚洲高清视频一视频二视频三| 亚洲一区二区三区写真| 亚洲国产精品18久久久久久 | 亚洲人成亚洲人成在线观看| 亚洲春色在线视频| 国产日产亚洲系列最新| 国产精品无码亚洲一区二区三区| 亚洲最大免费视频网| 久久精品国产亚洲av麻豆图片| 亚洲国产精品一区二区久久| 亚洲激情校园春色| 亚洲综合一区无码精品| 日韩色日韩视频亚洲网站| 国产精品亚洲美女久久久 | 亚洲人xxx日本人18|