Nio學習筆記(大部分網上摘抄)

来源:https://www.cnblogs.com/yangFly/archive/2019/12/04/11985421.html
-Advertisement-
Play Games

Nio與IO的區別 原有的 IO 是面向流的、阻塞的,NIO 則是面向塊的、非阻塞的。 1.IO流每次從流中讀一個或多個位元組,直至讀完所有位元組,他們沒有被緩存在其他地方,並且,IO流不能移動流中的數據,如果需要前後移動從流中讀取的教據,需要先將它緩存到一個緩衝區。Java NIO的緩衝導向方法略有不 ...


Nio與IO的區別

  原有的 IO 是面向流的、阻塞的,NIO 則是面向塊的、非阻塞的。

   1.IO流每次從流中讀一個或多個位元組,直至讀完所有位元組,他們沒有被緩存在其他地方,並且,IO流不能移動流中的數據,如果需要前後移動從流中讀取的教據,需要先將它緩存到一個緩衝區。Java NIO的緩衝導向方法略有不同。數據讀取到一個它稍後處理的緩衝區,霱要時可在緩衝區中前後移動。這就增加了處理過程中的靈活性。但是,還需要檢查是否該緩衝區中包含所有您需要處理的數裾。而且,需確保當更多的數據讀入緩衝區時,不要覆蓋緩衝區里尚未處理的數據。

 

   2.Java IO的各種流是阻塞的。這意味著,當一個線程調用read() 或 write()時,該線程被阻塞,直到有一些數據被讀取,或數據完全寫入。該線程在此期間不能再乾任何事情了。 Java NIO的非阻塞模式,使一個線程從某通道發送請求讀取數據,但是它僅能得到目前可用的數據,如果目前沒有數據可用時,就什麼都不會獲取。而不是保持線程阻塞,所以直至數據變的可以讀取之前,該線程可以繼續做其他的事情。 非阻塞寫也是如此。一個線程請求寫入一些數據到某通道,但不需要等待它完全寫入,這個線程同時可以去做別的事情。 線程通常將非阻塞IO的空閑時間用於在其它通道上執行IO操作,所以一個單獨的線程現在可以管理多個輸入和輸出通道(channel)。、

通道Channel

  NIO的通道類似於流,但有些區別如下:

    1. 通道可以同時進行讀寫,而流只能讀或者只能寫

    2. 通道可以實現非同步讀寫數據

    3. 通道可以從緩衝讀數據,也可以寫數據到緩衝: 

緩衝區Buffer類

  緩衝區是一個對象,有四個基本屬性,Nio的讀寫都是利用Buffer來實現的,簡而言之,讀取數據先從緩衝區讀,寫數據也是先寫入緩衝區的。我們最常用的是ByteBuffer這個實現類,對於Java中的基本類型都有一個對應的Buffer實現類與之對應,如CharBuffer,DoubleBuffer等等

    1丶其中的四個屬性的含義分別如下:
    容量(Capacity):緩衝區能夠容納的數據元素的最大數量。這一個容量在緩衝區創建時被設定,並且永遠不能改變。
    上界(Limit):緩衝區的第一個不能被讀或寫的元素。或者說,緩衝區中現存元素的計數。
    位置(Position):下一個要被讀或寫的元素的索引。位置會自動由相應的 get( )和 put( )函數更新。
    標記(Mark):下一個要被讀或寫的元素的索引。位置會自動由相應的 get( )和 put( )函數更新。
          2丶Buffer的常見方法如下所示:  

    flip(): 寫模式轉換成讀模式
    rewind():將 position 重置為 0 ,一般用於重覆讀。
    clear() :
    compact(): 將未讀取的數據拷貝到 buffer 的頭部位。
    mark(): reset():mark 可以標記一個位置, reset 可以重置到該位置

   3丶讀取操作

 1 FileInputStream inputStream = new FileInputStream("E:\\A.txt");
 2         /**
 3          * 拿到通道
 4          */
 5         FileChannel channel = inputStream.getChannel();
 6 
 7         /**
 8          * 創建緩存區
 9          */
10         ByteBuffer buffer = ByteBuffer.allocate(1024);
11 
12         /**
13          * 讀取數據到緩衝區
14          */
15         channel.read(buffer);
16 
17         buffer.flip();
18 
19         while (buffer.remaining() > 0){
20             byte b = buffer.get();
21             System.out.println(((char)b));
22         }
23         /**
24          * 關閉流
25          */
26         inputStream.close();
View Code

            4丶寫入操作

 1 static private final byte message[] = { 83,83,83,83,83,83 };
 2 
 3     static public void main( String args[] ) throws Exception {
 4         FileOutputStream fout = new FileOutputStream( "e:\\A.txt" );
 5 
 6         FileChannel fc = fout.getChannel();
 7 
 8         ByteBuffer buffer = ByteBuffer.allocate( 1024 );
 9 
10         for (int i=0; i<message.length; ++i) {
11             buffer.put( message[i] );
12         }
13 
14         buffer.flip();
15 
16         fc.write( buffer );
17 
18         fout.close();
19     }
View Code

選擇器Selector

  可以檢測多個NIO channel,看看讀或者寫事件是否就緒。多個Channel以事件的方式可以註冊到同一個Selector,從而達到用一個線程處理多個請求成為可能。

  使用NIO中非阻塞IO編寫伺服器處理程式,有三個步驟

    1.向Selector對象註冊感興趣的事件

    2.從Selector中獲取感興趣的事件

    3.根據不同事件進行相應的處理

 

 簡單API介紹

  open:創建selector
       selectKeys:獲取可用channel的集合
       select:選擇就緒的通道

簡單聊天室實現思路代碼

伺服器代碼

 

  1 public class NioServer {
  2 
  3 
  4     public void start() throws Exception {
  5         /**
  6          * 1.創建selector
  7          */
  8         Selector selector = Selector.open();
  9         /**
 10          * 2.通過ServerSocketChannel創建channel
 11          */
 12         ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
 13 
 14         /**
 15          * 3.為channel通道綁定監聽埠
 16          */
 17         serverSocketChannel.bind(new InetSocketAddress(8000));
 18         /**
 19          * 4.設置channel 為非阻塞模式
 20          */
 21         serverSocketChannel.configureBlocking(false);
 22         /**
 23          * 5.將channel 註冊到selector,監聽連接
 24          */
 25         serverSocketChannel.register(selector,SelectionKey.OP_ACCEPT);
 26         System.out.println("伺服器啟動成功");
 27         /**
 28          * 6.迴圈等待新接入的連接
 29          */
 30         for(;;){
 31             int select = selector.select();
 32             if (select == 0){
 33                 continue;
 34             }
 35 
 36             /**
 37              * 7.獲取可用channel的集合
 38              */
 39             Set<SelectionKey> keys = selector.selectedKeys();
 40             Iterator<SelectionKey> iterator = keys.iterator();
 41             while (iterator.hasNext()){
 42                 SelectionKey selectionKey = (SelectionKey) iterator.next();
 43                 /**
 44                  * 8.移除selctionKey
 45                  */
 46                 iterator.remove();
 47                 /**
 48                  * 處理具體業務邏輯
 49                  */
 50                 /**
 51                  * 接入事件
 52                  */
 53                 if (selectionKey.isAcceptable()){
 54                     acceptHandler(serverSocketChannel,selector);
 55                 }
 56                 /**
 57                  * 可讀事件
 58                  */
 59                 if(selectionKey.isReadable()){
 60                     readHandler(selectionKey, selector);
 61                 }
 62             }
 63 
 64 
 65         }
 66 
 67 
 68         /**
 69          * 根據就緒狀態,調用對應方法處理業務邏輯
 70          */
 71 
 72     }
 73 
 74     /**
 75      * 接入事件處理器
 76      */
 77     private void acceptHandler(ServerSocketChannel serverSocketChannel, Selector selector) throws Exception {
 78         /**
 79          * 如果是接入事件 創建serverSocket
 80          */
 81         SocketChannel socketChannel = serverSocketChannel.accept();
 82         /**
 83          * 設置非阻塞
 84          */
 85         socketChannel.configureBlocking(false);
 86         /**
 87          * 註冊進selector中
 88          */
 89         socketChannel.register(selector, SelectionKey.OP_READ);
 90         /**
 91          * 回覆服務端信息
 92          */
 93         socketChannel.write(Charset.forName("UTF-8").encode("你與聊天室里其他人都不是朋友關係,請註意隱私安全"));
 94 
 95     }
 96 
 97     private void  readHandler(SelectionKey selectionKey, Selector selector) throws Exception{
 98         /**
 99          * 要用selectionKey中獲取已經就緒的channel
100          */
101         SocketChannel channel = (SocketChannel)selectionKey.channel();
102         /**
103          * 創建buffer
104           */
105         ByteBuffer buffer = ByteBuffer.allocate(1024);
106         /**
107          * 迴圈讀取客戶端數據
108          */
109         String request = "";
110         while (channel.read(buffer) > 0){
111             /**
112              * 切換讀模式
113              */
114             buffer.flip();
115             /**
116              * 讀取buffer中的內容
117              */
118             request  += Charset.forName("UTF-8").decode(buffer);
119 
120         }
121         /**
122          * 講channel註冊到selector上
123          */
124         channel.register(selector, SelectionKey.OP_READ);
125         /**
126          * 講客戶端發送的請求信息,廣播給其他客戶端
127          */
128         if (request.length() > 0){
129             broadCast(selector, channel, request);
130         }
131     }
132 
133     private void broadCast(Selector selector, SocketChannel socketChannel, String request){
134         /**
135          * 獲取到已接入的客戶端hannel
136          */
137         Set<SelectionKey> selectionKeys = selector.keys();
138         selectionKeys.forEach(selectionKey -> {
139             Channel channel = selectionKey.channel();
140             if (channel  instanceof SocketChannel &&
141                     channel != socketChannel){
142                 try {
143                     //將信息發送到channel客戶端
144                     ((SocketChannel) channel).write(Charset.forName("UTF-8").encode(request));
145                 } catch (IOException e) {
146                     e.printStackTrace();
147                 }
148             }
149         });
150         /**
151          * 迴圈向所有channel廣播信息
152          */
153     }
154     /**
155      *
156      * @param args
157      */
158     public static void main(String[] args) throws Exception {
159         NioServer server = new NioServer();
160         server.start();
161     }
162 }
View Code

 

客戶端代碼

 1 public class NioClient {
 2 
 3 
 4     public void start() throws Exception {
 5         /**
 6          * 連接伺服器
 7          */
 8         SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 8000));
 9         /**
10          * 接收伺服器地址
11          */
12         Selector selector = Selector.open();
13         socketChannel.configureBlocking(false);
14         socketChannel.register(selector, SelectionKey.OP_READ);
15         new Thread(new NioClientHandler(selector)).start();
16         /**
17          * 向伺服器發送數據
18          */
19         Scanner scanner = new Scanner(System.in);
20         while (scanner.hasNextLine()){
21             String next = scanner.nextLine();
22             if (StringUtils.isNotBlank(next)){
23                 socketChannel.write(Charset.forName("UTF-8").encode(next));
24             }
25         }
26     }
27 
28     public static void main(String[] args) throws Exception {
29         new NioClient().start();
30     }
31 }
View Code

客戶端線程類

 1 public class NioClientHandler implements Runnable {
 2 
 3     private Selector selector;
 4 
 5     public NioClientHandler(Selector selector) {
 6         this.selector = selector;
 7     }
 8 
 9     @Override
10     public void run() {
11         /**
12          * 迴圈等待新接入的連接
13          */
14         try {
15             for(;;){
16                 int select = 0;
17                 select = selector.select();
18 
19                 if (select == 0){
20                     continue;
21                 }
22 
23                 /**
24                  * 獲取可用channel的集合
25                  */
26                 Set<SelectionKey> keys = selector.selectedKeys();
27                 Iterator<SelectionKey> iterator = keys.iterator();
28                 while (iterator.hasNext()){
29                     SelectionKey selectionKey = (SelectionKey) iterator.next();
30                     /**
31                      * 移除selctionKey
32                      */
33                     iterator.remove();
34                     /**
35                      * 可讀事件
36                      */
37                     if(selectionKey.isReadable()){
38                         readHandler(selectionKey, selector);
39                     }
40                 }
41             }
42         } catch (Exception e) {
43             e.printStackTrace();
44         }
45 
46 
47     }
48 
49     private void  readHandler(SelectionKey selectionKey, Selector selector) throws Exception{
50         /**
51          * 要用selectionKey中獲取已經就緒的channel
52          */
53         SocketChannel channel = (SocketChannel)selectionKey.channel();
54         /**
55          * 創建buffer
56          */
57         ByteBuffer buffer = ByteBuffer.allocate(1024);
58         /**
59          * 迴圈讀取客戶端數據
60          */
61         String request = "";
62         while (channel.read(buffer) > 0){
63             /**
64              * 切換讀模式
65              */
66             buffer.flip();
67             /**
68              * 讀取buffer中的內容
69              */
70             request  += Charset.forName("UTF-8").decode(buffer);
71 
72         }
73         /**
74          * 講channel註冊到selector上
75          */
76         channel.register(selector, SelectionKey.OP_READ);
77         /**
78          * 講客戶端發送的請求信息,廣播給其他客戶端
79          */
80         if (request.length() > 0){
81             System.out.println(request);
82         }
83     }
84 }
View Code

 

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 01 ++、 運算符重載函數的格式 自增運算符和自減運算符是有前置和後置之分的,如: 為了區分所重載的是前置運算符還是後置運算符,C++規定: 前置運算符作為 一元 運算符重載,重載為成員函數的格式如下: 後置運算符作為 二元 運算符重載,多寫一個 沒用 的參數,重載為成員函數的個數如下: 02 討 ...
  • Java基礎 做java開發,java基礎是最需要下功夫的一項。在校招時最註重的就是基礎,拿不出像樣的項目沒關係,但是基礎萬萬不可不牢固。 JavaWeb基礎 JavaWeb是一系列技術的綜合,也是大多數Java學習者日後的技術方向。及早的瞭解JavaWeb也有利於更深層面理解,Java在完整的應用 ...
  • [TOC] cookie與session cookie介紹 HTTP協議 是無狀態的,每次請求連接都是不保存客戶端狀態的,cookie就是用來保存客戶端狀態的。試想一下,如果每次登錄一個網站,每次跳轉頁面都不會記錄我的信息,都要求重新輸入密碼,是不是很不爽? Cookie具體指的是一段小信息,它是服 ...
  • 1.Math.random Math.random()*10 輸出隨機變數方法,使用:"Math.random()*數量" 如:(int)(Math.random()*10); //隨機取一個10以內的整數 例如:定義一個隨機1到5(取不到5)的變數 [1,5) Math.random()*(n-m ...
  • tkinter事件鍵盤綁定 1 from tkinter import * 2 3 root=Tk() 4 5 #創建一個框架,在這個框架中響應事件 6 frame=Frame(root, 7 width=200,height=200, 8 background='green') 9 10 def ...
  • 本文源碼: "GitHub·點這裡" || "GitEE·點這裡" 一、Spring事務管理 1、基礎描述 事務管理的本質就是封裝了資料庫對事務支持的操作,使用JDBC的事務管理機制,就是利用 對象完成對事務的提交和回滾。 2、事務常見概念 事務 事務是指作為單個邏輯工作單元執行的一系列操作(SQL ...
  • https://blog.csdn.net/Smile__1/article/details/103393618 ...
  • 前言本文的文字及圖片來源於網路,僅供學習、交流使用,不具有任何商業用途,版權歸原作者所有,如有問題請及時聯繫我們以作處理。 首先我們來看 Mac版 按照需求大家依次安裝,如果你還沒學到數據分析,建議你先學好Pytho基礎和爬蟲再來。可以去小編的Python交流.裙 :一久武其而而流一思(數字的諧音) ...
一周排行
    -Advertisement-
    Play Games
  • C#TMS系統代碼-基礎頁面BaseCity學習 本人純新手,剛進公司跟領導報道,我說我是java全棧,他問我會不會C#,我說大學學過,他說這個TMS系統就給你來管了。外包已經把代碼給我了,這幾天先把增刪改查的代碼背一下,說不定後面就要趕鴨子上架了 Service頁面 //using => impo ...
  • 委托與事件 委托 委托的定義 委托是C#中的一種類型,用於存儲對方法的引用。它允許將方法作為參數傳遞給其他方法,實現回調、事件處理和動態調用等功能。通俗來講,就是委托包含方法的記憶體地址,方法匹配與委托相同的簽名,因此通過使用正確的參數類型來調用方法。 委托的特性 引用方法:委托允許存儲對方法的引用, ...
  • 前言 這幾天閑來沒事看看ABP vNext的文檔和源碼,關於關於依賴註入(屬性註入)這塊兒產生了興趣。 我們都知道。Volo.ABP 依賴註入容器使用了第三方組件Autofac實現的。有三種註入方式,構造函數註入和方法註入和屬性註入。 ABP的屬性註入原則參考如下: 這時候我就開始疑惑了,因為我知道 ...
  • C#TMS系統代碼-業務頁面ShippingNotice學習 學一個業務頁面,ok,領導開完會就被裁掉了,很突然啊,他收拾東西的時候我還以為他要旅游提前請假了,還在尋思為什麼回家連自己買的幾箱飲料都要叫跑腿帶走,怕被偷嗎?還好我在他開會之前拿了兩瓶芬達 感覺感覺前面的BaseCity差不太多,這邊的 ...
  • 概述:在C#中,通過`Expression`類、`AndAlso`和`OrElse`方法可組合兩個`Expression<Func<T, bool>>`,實現多條件動態查詢。通過創建表達式樹,可輕鬆構建複雜的查詢條件。 在C#中,可以使用AndAlso和OrElse方法組合兩個Expression< ...
  • 閑來無聊在我的Biwen.QuickApi中實現一下極簡的事件匯流排,其實代碼還是蠻簡單的,對於初學者可能有些幫助 就貼出來,有什麼不足的地方也歡迎板磚交流~ 首先定義一個事件約定的空介面 public interface IEvent{} 然後定義事件訂閱者介面 public interface I ...
  • 1. 案例 成某三甲醫預約系統, 該項目在2024年初進行上線測試,在正常運行了兩天後,業務系統報錯:The connection pool has been exhausted, either raise MaxPoolSize (currently 800) or Timeout (curren ...
  • 背景 我們有些工具在 Web 版中已經有了很好的實踐,而在 WPF 中重新開發也是一種費時費力的操作,那麼直接集成則是最省事省力的方法了。 思路解釋 為什麼要使用 WPF?莫問為什麼,老 C# 開發的堅持,另外因為 Windows 上已經裝了 Webview2/edge 整體打包比 electron ...
  • EDP是一套集組織架構,許可權框架【功能許可權,操作許可權,數據訪問許可權,WebApi許可權】,自動化日誌,動態Interface,WebApi管理等基礎功能於一體的,基於.net的企業應用開發框架。通過友好的編碼方式實現數據行、列許可權的管控。 ...
  • .Net8.0 Blazor Hybird 桌面端 (WPF/Winform) 實測可以完整運行在 win7sp1/win10/win11. 如果用其他工具打包,還可以運行在mac/linux下, 傳送門BlazorHybrid 發佈為無依賴包方式 安裝 WebView2Runtime 1.57 M ...