成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

一篇文章讀不懂:IO vs. NIO

存儲 存儲軟件
處理輸入和輸出是Java程序員的常見任務,本教程中,我們將介紹 原始的 java.io (IO) 庫和較新的 java.nio (NIO) 庫 以及它們在通過網絡進行通信時的區(qū)別。.

[[320131]]

1. 概覽

處理輸入和輸出是Java程序員的常見任務,本教程中,我們將介紹 原始的 java.io (IO) 庫和較新的 java.nio (NIO) 庫 以及它們在通過網絡進行通信時的區(qū)別。.

2. 關鍵特性

讓我們先來看看這兩個包的關鍵特性。

2.1. IO – java.io

java.io 包是在Java 1.0引入的,而Reader 則是在 Java 1.1中引入。它提供:

  • InputStream 和 OutputStream – 一次提供一個字節(jié)的數(shù)據(jù)。
  • Reader 和 Writer – 包裝流
  • 阻塞模式(blocking mode) – 等待完整的消息

2.2. NIO – java.nio

java.nio 包在Java 1.4中被引入 并在 Java 1.7 (NIO.2) 更新了,其中包含 增強的文件操作 和 ASynchronousSocketChannel。它提供 :

  • Buffer – 一個讀取數(shù)據(jù)塊
  • CharsetDecoder – 用于將原始字節(jié)映射到可讀字符/從可讀字符映射原始字節(jié)
  • Channel – 與外界溝通
  • Selector – 在 SelectableChannel 上啟用多路復用,并提供對任何準備好進行I/O的 Channels 的訪問
  • 非阻塞模式(non-blocking mode) – 讀取任何準備好的東西

現(xiàn)在,讓我們看看在向服務器發(fā)送數(shù)據(jù)或讀取其響應時如何使用這些包。

3. 配置測試服務器

在這里,我們將使用 WireMock 來模擬另一臺服務器,以便我們可以獨立運行測試。

配置這臺服務器來監(jiān)聽請求,并像真正的web服務器一樣向我們發(fā)送響應。同時我們還將使用動態(tài)端口,這樣就不會與本地計算機上的任何服務沖突。

讓我們添加WireMock Maven依賴項到 test scope:

Let's add the Maven dependency for WireMock with test scope:

  1. <dependency> 
  2.     <groupId>com.github.tomakehurst</groupId> 
  3.     <artifactId>wiremock-jre8</artifactId> 
  4.     <version>2.26.3</version> 
  5.     <scope>test</scope> 
  6. </dependency> 

 

在測試類中,讓我們定義一個 JUnit*@Rule* 來在空閑端口上啟動 WireMock 。然后,我們將對其進行配置,使其在要求預定義資源時返回一個 HTTP 200 響應,消息體為 JSON 格式的文本:

  1. @Rule public WireMockRule wireMockRule = new WireMockRule(wireMockConfig().dynamicPort()); 
  2.   
  3. private String REQUESTED_RESOURCE = "/test.json"
  4.   
  5. @Before 
  6. public void setup() { 
  7.     stubFor(get(urlEqualTo(REQUESTED_RESOURCE)) 
  8.       .willReturn(aResponse() 
  9.       .withStatus(200) 
  10.       .withBody("{ \"response\" : \"It worked!\" }"))); 

現(xiàn)在已經建立了模擬服務器,我們準備運行一些測試。

4. Blocking IO – java.io

我們可通過從網站上讀取一些數(shù)據(jù)來了解原始的阻塞IO模型是如何工作的,例如:使用一個 java.net.Socket 來訪問操作系統(tǒng)的一個端口。

4.1. 發(fā)送請求(Request)

在這個例子中,我們將創(chuàng)建一個GET請求來檢索資源。首先,創(chuàng)建一個 Socket 來訪問我們的WireMock服務器正在監(jiān)聽的端口:

  1. Socket socket = new Socket("localhost", wireMockRule.port() 

對于普通的 HTTP 或 HTTPS 通信,端口應該是 80 或 443 。但是,在本例中,我們使用wireMockRule.port() 來訪問前面設置的動態(tài)端口?,F(xiàn)在,我們在套接字上打開一個 OutputStream ,包裝在 OutputStreamWriter 中,并將其傳遞給 PrintWiter 來編寫我們的消息。確保刷新緩沖區(qū)以便發(fā)送我們的請求:

  1. OutputStream clientOutput = socket.getOutputStream(); 
  2. PrintWriter writer = new PrintWriter(new OutputStreamWriter(clientOutput)); 
  3. writer.print("GET " + TEST_JSON + " HTTP/1.0\r\n\r\n"); 
  4. writer.flush(); 

4.2. 等待響應(Response)

打開套接字上的 InputStream 來獲取響應,使用 BufferedReader 讀取流,并將其存儲在 StringBuilder 中:

  1. InputStream serverInput = socket.getInputStream(); 
  2. BufferedReader reader = new BufferedReader(new InputStreamReader(serverInput)); 
  3. StringBuilder ourStore = new StringBuilder(); 

我們使用 reader.readLine() 來阻塞,等待一個完整的行,然后將該行追加到我們的存儲中。我們將一直讀取,直到得到一個空值,它指示流的結尾:

  1. for (String line; (line = reader.readLine()) != null;) { 
  2.    ourStore.append(line); 
  3.    ourStore.append(System.lineSeparator()); 

5. Non-Blocking IO – java.nio

現(xiàn)在,讓我們看看 NIO包 的非阻塞IO模型是如何與同一個例子一起工作的。

這次,我們將創(chuàng)建一個 java.nio.channel.SocketChannel 來訪問服務器上的端口,而不是java.net.Socket,并向它傳遞一個InetSocketAddress。

5.1. 發(fā)送 Request

首先, 打開 SocketChannel:

  1. InetSocketAddress address = new InetSocketAddress("localhost", wireMockRule.port()); 
  2. SocketChannel socketChannel = SocketChannel.open(address); 

現(xiàn)在,讓我們使用一個標準的UTF-8字符集 來編碼和編寫我們的消息:

  1. Charset charset = StandardCharsets.UTF_8; 
  2. socket.write(charset.encode(CharBuffer.wrap("GET " + REQUESTED_RESOURCE + " HTTP/1.0\r\n\r\n"))); 

5.2. 讀取 Response

發(fā)送請求后,我們可以使用原始緩沖區(qū)以非阻塞模式讀取響應。

既然要處理文本,那么我們需要一個 ByteBuffer 來處理原始字節(jié),一個CharBuffer 用來轉換字符(借助 CharsetDecoder):

  1. ByteBuffer byteBuffer = ByteBuffer.allocate(8192); 
  2. CharsetDecoder charsetDecoder = charset.newDecoder(); 
  3. CharBuffer charBuffer = CharBuffer.allocate(8192); 

如果數(shù)據(jù)是以多字節(jié)字符集發(fā)送的,CharBuffer 將有剩余空間。

注意,如果需要特別快的性能,我們可以使用 ByteBuffer.allocateDirect() 在本機內存中創(chuàng)建一個MappedByteBuffer。然而,在我們的例子中,從標準堆中使用 allocate() 已經足夠快了。

在處理緩沖區(qū)時,我們需要知道緩沖區(qū)有多大(capacity),我們在緩沖區(qū)中的位置(current position),以及我們能走多遠(limit)。

所以,我們從SocketChannel中讀取,將它傳遞給 ByteBuffer 來存儲我們的數(shù)據(jù)。從 SocketChannel讀取將以 ByteBuffer的當前位置為下一個要寫入的字節(jié)(就在寫入最后一個字節(jié)之后)結束,但其限制(limit)不變:

  1. socketChannel.read(byteBuffer) 

Our SocketChannel.read() 返回可以寫入緩沖區(qū)的讀取字節(jié)數(shù) ,如果斷開連接,則會變成 -1.

當緩沖區(qū)由于尚未處理其所有數(shù)據(jù)而沒有剩余空間時,SocketChannel.read() 將返回讀取的零字節(jié),但buffer.position() 仍將大于零。

確保從緩沖區(qū)的正確位置開始讀取, 我們將使用 Buffer.flip() 來設置 ByteBuffer 的當前位置為0 以及它對 SocketChannel 寫入的最后一個字節(jié)的限制。然后,我們將使用 storeBufferContents 方法保存緩沖區(qū)內容,稍后我們將查看該方法。最后,使用 buffer.compact() 壓縮緩沖區(qū)并設置當前位置,以便下次從 SocketChannel 讀取。

由于數(shù)據(jù)可能部分到達,需要用終止條件將緩沖區(qū)讀取代碼包裝成一個循環(huán),以檢查套接字是否仍然連接,或者是否已斷開連接,但緩沖區(qū)中仍有數(shù)據(jù):

  1. while (socketChannel.read(byteBuffer) != -1 || byteBuffer.position() > 0) { 
  2.     byteBuffer.flip(); 
  3.     storeBufferContents(byteBuffer, charBuffer, charsetDecoder, ourStore); 
  4.     byteBuffer.compact(); 

別忘了關閉套接字(除非我們在try with resources塊中打開它):

  1. socketChannel.close(); 

5.3. Buffer存儲數(shù)據(jù)

來自服務器的響應將包含頭,這可能會使數(shù)據(jù)量超過緩沖區(qū)的大小。因此,我們將使用StringBuilder在消息到達時構建完整的消息。為了存儲我們的消息,我們首先將原始字節(jié)解碼為我們的 CharBuffer 中的字符。然后翻轉指針,以便讀取字符數(shù)據(jù),并將其附加到可擴展的 StringBuilder. 最后,清除CharBuffer以準備下一個寫/讀循環(huán)。現(xiàn)在,讓我們實現(xiàn)傳入緩沖區(qū)的完整 storeBufferContents() 方法,CharsetDecoder 和 StringBuilder:

  1. void storeBufferContents(ByteBuffer byteBuffer, CharBuffer charBuffer,  
  2.   CharsetDecoder charsetDecoder, StringBuilder ourStore) { 
  3.     charsetDecoder.decode(byteBuffer, charBuffer, true); 
  4.     charBuffer.flip(); 
  5.     ourStore.append(charBuffer); 
  6.     charBuffer.clear(); 

6. 總結

本文中, 我們已經看到原始java.io模型如何阻塞,等待請求,并使用 Streams 來操作它接收到的數(shù)據(jù)。相反,java.nio庫允許使用Buffers和Channels進行非阻塞通信,并且可以提供直接內存訪問以獲得更快的性能。然而,這種速度帶來了處理緩沖區(qū)的額外復雜性。

在本文中,我們看到了原始 java.io 模型如何阻塞,如何等待請求并使用Streams來處理它接收到的數(shù)據(jù)。相反,java.nio庫允許使用Buffers和Channels進行非阻塞通信,并且可以提供直接內存訪問以獲得更快的性能。然而,這種速度帶來了處理緩沖區(qū)的額外復雜性。

一如既往, 代碼 over on GitHub.

 

責任編輯:武曉燕 來源: 鍋外的大佬
相關推薦

2023-05-08 08:21:15

JavaNIO編程

2020-10-09 08:15:11

JsBridge

2020-10-23 07:56:04

Java中的IO流

2022-02-21 09:44:45

Git開源分布式

2019-04-17 15:16:00

Sparkshuffle算法

2024-06-25 08:18:55

2021-06-30 00:20:12

Hangfire.NET平臺

2023-05-12 08:19:12

Netty程序框架

2021-04-09 08:40:51

網絡保險網絡安全網絡風險

2017-09-05 08:52:37

Git程序員命令

2022-02-23 09:36:11

GoRuby編程語言

2022-02-17 08:35:59

OLTPOLAP數(shù)據(jù)倉庫

2020-10-22 08:25:22

JavaScript運作原理

2019-01-09 10:04:16

2020-02-28 11:29:00

ElasticSear概念類比

2021-07-01 10:01:16

JavaLinkedList集合

2017-08-22 16:20:01

深度學習TensorFlow

2013-04-15 10:59:08

iOS開發(fā)ARC版本說明

2025-01-21 07:00:00

2022-12-14 08:03:27

CSS變量前端
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 日韩在线免费播放 | 午夜成人免费电影 | 国产精品久久久久久久一区探花 | 午夜久久久久久久久久一区二区 | 国产精品毛片 | 亚洲人a | 亚洲一区二区三区乱码aⅴ 四虎在线视频 | 国产精品久久久久久久久久久久久 | 欧美日韩电影一区 | 国产第一区二区 | 懂色av蜜桃av | 成人欧美一区二区三区色青冈 | 欧美性video| 亚洲精品电影在线观看 | 欧美一级免费看 | 999精品视频在线观看 | 久久国产精品一区二区三区 | 精品乱人伦一区二区三区 | 欧美精品在线一区二区三区 | 国产精品不卡一区 | 国产精品美女久久久免费 | 久草网址 | 国内精品伊人久久久久网站 | 亚洲男人的天堂网站 | 亚洲一区中文字幕 | 国产电影一区二区在线观看 | 天天色综网 | 国产精品成人久久久久 | 草草视频在线观看 | 亚洲日本视频 | 日韩性生活网 | 亚洲午夜视频 | 美女福利视频 | 一级在线视频 | 久国久产久精永久网页 | 中文二区| 久久久久久国产精品久久 | 一区二区日韩 | 久久精品一区 | 国产91网址| 999久久久久久久 |