BIO就是傳統的socket編程。每有一個客戶端連入,服務端就須要另起線程爲其服務,很容易形成資源枯竭。html
Channel管道比做成鐵路,buffer緩衝區比做成火車(運載着貨物)java
public static void main(String[] args) { // 建立一個緩衝區 ByteBuffer byteBuffer = ByteBuffer.allocate(1024); // 添加一些數據到緩衝區中 String s = "Java3y"; byteBuffer.put(s.getBytes()); //切換成讀模式 byteBuffer.flip(); // 建立一個limit()大小的字節數組(由於就只有limit這麼多個數據可讀) byte[] bytes = new byte[byteBuffer.limit()]; // 將讀取的數據裝進咱們的字節數組中 byteBuffer.get(bytes); // 輸出數據 System.out.println(new String(bytes, 0, bytes.length)); }
// 1. 經過本地IO的方式來獲取通道 FileInputStream fileInputStream = new FileInputStream("F:\\3yBlog\\JavaEE經常使用框架\\Elasticsearch就是這麼簡單.md"); // 獲得文件的輸入通道 FileChannel inchannel = fileInputStream.getChannel(); // 2. jdk1.7後經過靜態方法.open()獲取通道 FileChannel.open(Paths.get("F:\\3yBlog\\JavaEE經常使用框架\\Elasticsearch就是這麼簡單2.md"), StandardOpenOption.WRITE);
複製文件編程
使用內存映射文件的方式實現文件複製的功能(直接操做緩衝區):設計模式
通道之間經過transfer()
實現數據的傳輸(直接操做緩衝區):數組
阻塞I/O:網絡
非阻塞I/O:併發
I/O多路複用:框架
在Linux下對文件的操做是利用文件描述符(file descriptor)來實現的。socket
在Linux下它是這樣子實現I/O複用模型的:調用select/poll/epoll/pselect
其中一個函數,傳入多個文件描述符,若是有一個文件描述符就緒,則返回,不然阻塞直到超時。函數
因此,I/O 多路複用的特色是經過一種機制一個進程能同時等待多個文件描述符,而這些文件描述符其中的任意一個進入讀就緒狀態,select()函數就能夠返回。select/epoll的優點並非對於單個鏈接能處理得更快,而是在於能處理更多的鏈接。
IO多路複用對應的設計模式:Reactor模式
http://www.javashuo.com/article/p-yeqleamk-kt.html
1、普通拷貝
read(file, tmp_buf, len); write(socket, tmp_buf, len);
能夠看到,普通的拷貝過程經歷了四次內核態和用戶態的切換(上下文切換),兩次CPU從內存中進行數據的讀寫過程,這種拷貝過程相對來講比較消耗系統資源。
2、零拷貝
內存映射方式(NIO中的map()就是用的這種):
tmp_buf = mmap(file, len); write(socket, tmp_buf, len);
能夠看到這種內存映射的方式減小了CPU的讀寫次數,可是用戶態到內核態的切換(上下文切換)依舊有四次(調用map()是兩次,調用write()是兩次),同時須要注意在進行這種內存映射的時候,有可能會出現併發線程操做同一塊內存區域而致使的嚴重的數據不一致問題,因此須要進行合理的併發編程來解決這些問題。
sendfile()方式(NIO中的transfer()就是用的這種):
sendfile(socket, file, len);
依舊有一次CPU進行數據拷貝,兩次用戶態和內核態的切換操做,相比較於內存映射的方式有了很大的進步,但問題是程序不能對數據進行修改,而只是單純地進行了一次數據的傳輸過程。
===========================
NIO:
https://juejin.im/post/5af942c6f265da0b7026050c
ZeroCopy:
https://blog.csdn.net/cringkong/article/details/80274148
https://www.jianshu.com/p/8c6b056f73ce