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
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...