這篇文章主要介紹了Java 非阻塞I/O使用方法,文中涉及非阻塞I/O的簡介,同時向大家展示了利用非阻塞I/O實現客戶端的方法,需要的朋友可以參考下。
絕大部分知識與實例來自O'REILLY的《Java網絡程式設計》(Java Network Programming,Fourth Edition,by Elliotte Rusty Harold(O'REILLY))。
非阻塞I/O簡介
非阻塞I/O(NIO)是處理高並發的一種手段。在高並發的情況下,創建和回收線程以及在線程間切換的開銷變得不容忽視,此時就可以使用非阻塞I/O技術。這種技術的核心思想是每次選取一個準備好的連接,盡快填入這個連接所能管理的盡可能多的數據,然後轉向下一個準備好的連接。
利用非阻塞I/O實作的客戶端
#一般情況下,客戶端不會需要處理很高數量的並發連接。事實上,非阻塞I/O主要是為伺服器設計的,但它也可以用在客戶端。由於客戶端的設計相比伺服器容易,因此以下先用客戶端來進行簡單示範。
首先介紹通道(channel)和緩衝區。非阻塞I/O中使用SocketChannel類別建立連線。要取得SocketChannel對象,需要將SocketAddress物件(通常會使用它的子類別InetSocketAddress)傳入它的靜態工廠方法open()。下面為一個範例:
SocketAddress address = new InetSocketAddress("127.0.0.1", 19); SocketChannel client = SocketChannel.open(address);
open()方法是阻塞的,因此這之後的程式碼在連線建立之前不會執行。如果連線無法建立,會拋出一個IOException異常。
連接建立之後就需要取得輸入和輸出。有別於傳統的getInputStream()與getOutputStream(),利用頻道,你可以直接寫入頻道本身。不是寫入一個位元組數組,而是要寫入一個ByteBuffer物件。 ByteBuffer物件透過ByteBuffer.allocate(int capacity)取得,capacity為緩衝區大小,單位為位元組:
##
ByteBuffer buffer = ByteBuffer.allocate(74);
#
WritableByteChannel out = Channels.newChannel(System.out);
buffer.flip(); out.write(buffer); buffer.clear();
實例1:利用非阻塞I/O實作的CharGenerator(字元產生器)用戶端
public static void createCharGeneratorServer(){ try(ServerSocket server = new ServerSocket(19)){ while(true){ try(Socket connection = server.accept()){ OutputStream out = connection.getOutputStream(); int firstPrintableCharacter = 33; int numberOfPrintableCharacter = 94; int numberOfCharactersPerLine = 72; int start = firstPrintableCharacter; while(true){ for(int i = start ; i < start + numberOfCharactersPerLine ; i++){ out.write (firstPrintableCharacter + (i - firstPrintableCharacter) % numberOfPrintableCharacter); } out.write('\r'); out.write('\n'); start = firstPrintableCharacter + (start + 1 - firstPrintableCharacter) % numberOfPrintableCharacter; } }catch (IOException e) { e.printStackTrace(); } } } catch (IOException e) { e.printStackTrace(); } }
try { SocketAddress address = new InetSocketAddress("127.0.0.1", 19); SocketChannel client = SocketChannel.open(address); ByteBuffer buffer = ByteBuffer.allocate(74); WritableByteChannel out = Channels.newChannel(System.out); while(client.read(buffer) != -1){ buffer.flip(); out.write(buffer); buffer.clear(); } } catch (IOException e) { e.printStackTrace(); } 输出(无限循环): ]^_`abcdefghijklmnopqrstuvwxyz{|}~!"#$%&'()*+,-./0123456789:;<=>?@ABCDEF ^_`abcdefghijklmnopqrstuvwxyz{|}~!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFG _`abcdefghijklmnopqrstuvwxyz{|}~!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGH `abcdefghijklmnopqrstuvwxyz{|}~!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHI abcdefghijklmnopqrstuvwxyz{|}~!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJ bcdefghijklmnopqrstuvwxyz{|}~!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJK
啟用非阻塞模式
while(true){ //这里可以写每次循环都要做的事,无论有没有读到数据 int n = client.read(buffer); if(n > 0){ buffer.flip(); out.write(buffer); buffer.clear(); }else if (n == -1) { //除非服务器故障,否则不会发生 break; } }
總結
以上是Java中關於非阻塞I/O的使用方法的詳細內容。更多資訊請關注PHP中文網其他相關文章!