JAVA的 IO NIO AIO筆記
阿新 • • 發佈:2017-08-13
實時通信 html 連接 selector web 協議棧 文件操作 情況 htm IO
linux內核將所有外部設備都看做一個文件來操作,對一個文件的讀寫會調用內核系統命令,放回一個file descriptor(文件描述符),
對一個socket的讀寫也會有相應的描述符,稱為socketfd
Java NIO的核心類庫多路復用器Selector就是基於epoll的多路復用技術實現
I/O多路復用技術通過把多個I/O的阻塞復用到同一個select的阻塞上,從而使得系統在單線程的情況下可以同時處理多個客戶端請求
epoll和select的原理比較類似,並做了很多重大改進
1 支持一個進程打開的socket描述符(FD)不受限制(僅受限於操作系統的最大文件句柄數),1GB內存的機器上大約是10萬個句柄左右,
具體值可以通過cat /proc/sys/fs/file- max查看
2 I/O效率不會隨著FD數目的增加而線性下降,socket集合的維護成本上,epoll只會對活躍的socket進行操作,因為在內核實現中,
epoll是根據每個fd上面的callback函數實現額,只有活躍的socket才會去主動調用callback函數
3 使用mmap加速內核與用戶空間的消息傳遞,epoll是通過內核和用戶空間mmap同一塊內存來實現的
JDK1.7升級了原來的NIO類
1 提供能夠批量獲取文件屬性的API,這些API具有平臺無關性,另外還提供了標準文件系統的SPI,供各個服務提供商擴展的實現
2 提供AIO功能,支持基於文件的異步I/O操作和針對網絡套接字的異步操作
3 完成了定義的通道功能,包括對配置和多播數據報的支持
同步阻塞I/O,阻塞的時間取決於對方I/O線程的處理速度和網絡I/O的傳輸速度
偽異步I/O
采用線程池和任務隊列可以實現一種叫做偽異步的I/O通信框架
缺陷,當對Socket的輸入流進行讀取操作的時候,它會一直阻塞下去,直到發生如下三件事:1有數據可讀2可用數據已經讀取完畢3發生空指針或者I/O異常
偽異步I/O實際上僅僅是對之前I/O線程模型的一個簡單優化,無法從根本上解決同步I/O導致的通信阻塞問題
NIO(Non-block I/O)
與Socket類和ServerSocket類相對應,NIO也提供了SocketChannel和ServerSocketChannel兩種不同的套接字通道實現,這兩種新增的通道同時支持阻塞和非阻塞兩種模式
NIO彌補了原來同步阻塞I/O的不足,在標準Java代碼中提供了高速的、面向塊的I/O
在NIO類庫中加入了Buffer(緩沖區)對象,體現了新庫與原I/O的一個重要區別,緩沖區不僅僅是一個數組,還提供了對數據的結構化訪問以及維護讀寫位置等信息
每一種Java基本類型(除了Boolean類型)都對應有一種緩沖區,大多數標準I/O操作都使用ByteBuffer
Channel是一個通道,通道與流的不同之處在於通道時雙向的,流只是在一個方向上移動,而通道可以用於讀、寫或者二者同時進行,Channel是全雙工的,
UNIX底層操作系統通道都是全雙工的,所以它可以更好的映射底層操作系統API
Channel分為兩大類:用於網絡讀寫的SelectableChannel和用於文件操作的FileChannel
多路復用器Selector
多路復用器提供選擇已經就緒的任務的能力,Selector會不斷地輪詢註冊在其上的Channel,如果某個Channel上面發生讀或者寫事件,這個Channel就處於就緒狀態,會被Selector輪詢出來,
然後通過SelectionKey可以獲取就緒Channel的集合,進行後續的I/O操作,由於JDK使用了epoll代替了傳統的select實現,所以它並沒有最大連接句柄1024/2048的限制
AIO
NIO 2.0引入了新的異步通道的概念,並提供了異步文件通道和異步套接字通道的實現,異步通道提供以下兩種方式獲取操作結果
1 通過java.util.concurrent.Future類來表示異步操作的結果
2 在執行異步操作的時候傳入一個java.nio.channels
它不需要通過多路復用器對註冊的通道進行輪詢操作即可以實現異步讀寫
Netty
TCP粘包拆包
使用LineBasedFrameDecoder和StringDecoder可以解決TCP粘包導致的讀半包問題,這兩者的組合就是按行切換的文本解碼器
DelimiterBasedFrameDecoder自動完成以分隔符做結束標誌的消息的解碼
FixedLengthFrameDecoder可以自動完成對定長消息的解碼
編解碼技術
基於JDK默認的序列化機制可以讓程序員避免操作底層的字節數組,序列化的目的主要是網絡傳輸和對象持久化
當進行跨進程服務調用時,需要把被傳輸的Java對象編碼為字節數組或者ByteBuffer對象,而當遠程服務讀取到ByteBuffer對象或字節數組時,需要將其 解碼為發送時的Java對象,這被稱為Java對象編解碼技術,Java序列化僅僅是Java編解碼技術的一種
采用JDK序列化機制編碼後的二進制數組大小是二進制編碼的5倍多
編解碼框架的優勢往往從以下幾個方面考量:是否支持跨語言,編碼後的碼流大小,編解碼的性能,類庫是否小巧方便使用
協議棧開發就是基於現有的基礎協議(eg http協議)進行的封裝擴展
WebSocket協議開發
HTTP協議的弊端 半雙工協議,在客戶端和服務端兩個方向上傳輸,但是不能同時傳輸;消息采用文本傳輸,冗長繁瑣;長時間輪詢
比較新的一種輪詢技術是Comet,使用AJAX,這種技術雖然可以達到雙向通信,但依然需要發出請求,而且普遍使用了長連接,會大笑消耗帶寬和資源
HTML5定義了WebSocket協議,能更好的節省服務器資源和帶寬並達到實時通信
JAVA的 IO NIO AIO筆記