1. 程式人生 > >java中NIO程式設計另一種實現超實用

java中NIO程式設計另一種實現超實用

  除了普通的Socket與ServerSocket實現的阻塞式通訊外,Java提供了非阻塞式通訊的NIO API。先看一下NIO的實現原理。

       從圖中可以看出,伺服器上所有Channel(包括ServerSocketChannel和SocketChannel)都需要向Selector註冊,而該Selector則負責監視這些Socket的IO狀態,當其中任意一個或者多個Channel具有可用的IO操作時,該Selector的select()方法將會返回大於0的整數,該整數值就表示該Selector上有多少個Channel具有可用的IO操作,並提供了selectedKeys()方法來返回這些Channel對應的SelectionKey集合。正是通過Selector,使得伺服器端只需要不斷地呼叫Selector例項的select()方法即可知道當前所有Channel是否有需要處理的IO操作。

看個demo

NClient.java

  1. import java.io.IOException;  
  2. import java.net.InetSocketAddress;  
  3. import java.nio.ByteBuffer;  
  4. import java.nio.channels.SelectionKey;  
  5. import java.nio.channels.Selector;  
  6. import java.nio.channels.SocketChannel;  
  7. import java.nio.charset.Charset;  
  8. import java.util.Scanner;  
  9. publicclass NClient {  
  10.     //定義檢測SocketChannel的Selector物件
  11.     private Selector selector=null;  
  12.     //定義處理編碼和解碼的字符集
  13.     private Charset charset=Charset.forName("UTF-8");  
  14.     //客戶端SocketChannel
  15.     private SocketChannel sc=null;  
  16.     publicvoid init() throws IOException{  
  17.         selector=Selector.open();  
  18.         InetSocketAddress isa=new InetSocketAddress("127.0.0.1",30000);  
  19.         //呼叫open靜態方法建立連線到指定主機的SocketChannel
  20.         sc=SocketChannel.open(isa);  
  21.         //設定該sc以非阻塞方式工作
  22.         sc.configureBlocking(false);  
  23.         //將Socketchannel物件註冊到指定Selector
  24.         sc.register(selector, SelectionKey.OP_READ);  
  25.         //啟動讀取伺服器端資料的執行緒
  26.         new ClientThread().start();  
  27.         //建立鍵盤輸入流
  28.         Scanner scan=new Scanner(System.in);  
  29.         while(scan.hasNextLine()){  
  30.             //讀取鍵盤輸入
  31.             String line=scan.nextLine();  
  32.             //將鍵盤輸入的內容輸出到SocketChannel中
  33.             sc.write(charset.encode(line));  
  34.         }  
  35.     }  
  36.     //定義讀取伺服器資料的執行緒
  37.     privateclass ClientThread extends Thread{  
  38.         publicvoid run(){  
  39.             try{  
  40.                 while(selector.select()>0){  
  41.                     //遍歷每個有可用IO操作Channel對應的SelectionKey
  42.                     for(SelectionKey sk:selector.selectedKeys()){  
  43.                         //刪除正在處理的SelectionKey
  44.                         selector.selectedKeys().remove(sk);  
  45.                         //如果該SelectionKey對應的Channel中有可讀的資料
  46.                         if(sk.isReadable()){  
  47.                             //使用NIO讀取channel中的資料
  48.                             SocketChannel sc=(SocketChannel) sk.channel();  
  49.                             ByteBuffer buff=ByteBuffer.allocate(1024);  
  50.                             String content="";  
  51.                             while(sc.read(buff)>0){  
  52.                                 //sc.read(buff);
  53.                                 buff.flip();  
  54.                                 content+=charset.decode(buff);  
  55.                             }  
  56.                             //列印輸出讀取的內容
  57.                             System.out.println("聊天資訊"+content);  
  58.                             //為下一次讀取做準備
  59.                             sk.interestOps(SelectionKey.OP_READ);  
  60.                         }  
  61.                     }  
  62.                 }  
  63.             }catch(IOException ex){  
  64.                 ex.printStackTrace();  
  65.             }  
  66.         }  
  67.     }  
  68.     publicstaticvoid main(String[]args) throws IOException{  
  69.         new NClient().init();  
  70.     }  
  71. }  

NServer.java

  1. import java.io.IOException;  
  2. import java.net.InetSocketAddress;  
  3. import java.nio.ByteBuffer;  
  4. import java.nio.channels.Channel;  
  5. import java.nio.channels.SelectionKey;  
  6. import java.nio.channels.Selector;  
  7. import java.nio.channels.ServerSocketChannel;  
  8. import java.nio.channels.SocketChannel;  
  9. import java.nio.charset.Charset;  
  10. publicclass NServer {  
  11.     //用於檢測所有Channel狀態的Selector
  12.     private Selector selector=null;  
  13.     //定義實現編碼、解碼的字符集物件
  14.     private Charset charset=Charset.forName("UTF-8");  
  15.     publicvoid init() throws IOException{  
  16.         selector=Selector.open();  
  17.         //通過open方法來開啟一個未繫結的ServerSocketChannel例項
  18.         ServerSocketChannel server=ServerSocketChannel.open();  
  19.         InetSocketAddress isa=new InetSocketAddress("127.0.0.1",30000);  
  20.         //將該ServerSocketChannel繫結到指定ip地址
  21.         server.socket().bind(isa);  
  22.         //設定ServerSocket以非阻塞方式工作
  23.         server.configureBlocking(false);  
  24.         //將server註冊到指定Selector物件
  25.         server.register(selector, SelectionKey.OP_ACCEPT);  
  26.         while(selector.select()>0){  
  27.             //依次處理selector上的每個已選擇的SelectionKey
  28.             for(SelectionKey sk:selector.selectedKeys()){  
  29.                 //從selector上的已選擇Key集中刪除正在處理的SelectionKey
  30.                 selector.selectedKeys().remove(sk);  
  31.                 //如果sk對應的通訊包含客戶端的連線請求
  32.                 if(sk.isAcceptable()){  
  33.                     //呼叫accept方法接受連線,產生伺服器端對應的SocketChannel
  34.                     SocketChannel sc=server.accept();  
  35.                     //設定採用非阻塞模式
  36.                     sc.configureBlocking(false);  
  37.                     sc.register(selector, SelectionKey.OP_READ);  
  38.                     //將sk對應的Channel設定成準備接受其他請求
  39.                     sk.interestOps(SelectionKey.OP_ACCEPT);  
  40.                 }  
  41.                 //如果sk對應的通道有資料需要讀取
  42.                 if(sk.isReadable()){  
  43.                     //獲取該SelectionKey對應的Channel,該Channel中有可讀的資料
  44.                     SocketChannel sc=(SocketChannel) sk.channel();  
  45.                     //定義準備之星讀取資料的ByteBuffer
  46.                     ByteBuffer buff=ByteBuffer.allocate(1024);  
  47.                     String content="";  
  48.                     //開始讀取資料
  49.                     try{  
  50.                         while(sc.read(buff)>0){  
  51.                             buff.flip();  
  52.                             content+=charset.decode(buff);  
  53.                         }  
  54.                         //列印從該sk對應的Channel裡讀到的資料
  55.                         System.out.println("=========="+content);  
  56.                         //將sk對應的Channel設定成準備下一次讀取
  57.                         sk.interestOps(SelectionKey.OP_READ);  
  58.                         //如果捕捉到該sk對應的channel出現異常,即表明該channel對應的client出現了
  59.                         //異常,所以從selector中取消sk的註冊
  60.                     }catch(IOException e){  
  61.                         //從Selector中刪除指定的SelectionKey
  62.                         sk.cancel();  
  63.                         if(sk.channel()!=null){  
  64.                             sk.channel().close();  
  65.                         }  
  66.                     }  
  67.                     //如果content的長度大於0,即聊天資訊不為空
  68. 相關推薦

    javaNIO程式設計實現實用

      除了普通的Socket與ServerSocket實現的阻塞式通訊外,Java提供了非阻塞式通訊的NIO API。先看一下NIO的實現原理。        從圖中可以看出,伺服器上所有Channel(包括ServerSocketChannel和SocketCha

    Java模版方法的實現

    pan strategy 全部 相關 必須 rod () 抽象方法 rate   面試荔枝FM杯具,遂死磕AQS途中發現一個有趣的模版用法,記下來。   模版方法是很重要的設計模式,在數據訪問層、眾多的插件接口都可見其影子,一般的實現都是在模版中定義抽象方法並使用其方法進行

    java 多執行緒的實現方式

    private ThreadPoolExecutor threadPoolExecutor; /** * 獲取執行緒池 * @return */ private ThreadPoolExecutor getThreadPoolExecutor(){

    吸頂效果的實現

      前面介紹過一篇文章,是使用ItemDecoration來實現吸頂效果,使用起來很解耦,簡單,方便,但是優缺點是拓展性比較差,今天就通過另一種方式來實現吸頂效果,並且吸頂欄可以高度制定佈局和互動,步入正題,下面來實現它,先看看效果圖: 一、實現原理 頭部的內容位於R

    物聯網應用的數字孿生——實現物聯網數字孿生的全面的解決方案

    原文連結:http://www.oracle.com/us/solutions/inter...twins-for-iot-apps-wp-3491953.pdf 轉載於:https://blog.csdn.net/steelren/article/details/79198165 簡介

    101889I (LCA的實現

    題意:   Q次詢問,每次詢問必須包含特定邊的最小生成樹。 思路: 考慮 最淳樸的最小生成樹,如果加了一條特定邊,肯定是構成了一個環,那麼環外的邊肯定是不變的,要不然,根本就不可能選外面的那些邊了, 所以我們現在就是求這個環上的最小 生成樹,肯定是找樹上之前的 兩個點之

    利用IAT匯出OpenGL函式:OpenGL Loader的實現辦法

    利用這種辦法可以用50KB的DLL匯出OpenGL 3.3版本所有Core Profile函式, DLL比GLEW小很多, 根據glcorearb.h自動生成的程式碼與glLoadGen生成的程式碼差不多, 這部分程式碼包含的函式都是空實現,結合__declspec(dllexport,

    載入一個類時,其內部類是否同時被載入?引申出單例模式的實現方式...

    載入一個類時,其內部類是否同時被載入?下面我們做一個實驗來看一下。public class Outer { static { System.out.println("load outer class..."); } //靜態內部類 sta

    載入一個類時,其內部類是否同時被載入?引申出單例模式的實現方式

     載入一個類時,其內部類是否同時被載入?下面我們做一個實驗來看一下。  Java程式碼   1.    public class Outer {   2.        static {   3.            System.out.println("load o

    Java中文鍵樹的實現(附帶模糊查詢功能)

    首先在文章的開頭宣告一下哈,本文只是介紹一種Java蠻力鍵樹的實現,並沒有什麼高深的資料結構,所以資料量不超過百萬字元的可以參考,資料量太大的另請高明吧。另外,後面的鍵樹程式碼實際上不僅適用於中文儲存和查詢,只要是字串形式的資料都可以儲存。比如:“鋤禾日當午”、“a+你好啊234#jfjf”這樣形式

    程序和程式關係類比/ java執行緒是哪實現【清華大學】作業系統

    本文分三個小節 1 執行緒模型 2 執行緒的實現  3 java中執行緒是使用者執行緒,核心執行緒,輕量級程序??? 3.1 臨界區 互斥 3.2 訊號量 管程 前兩小節是來自作業系統。 第三小節:看到作業系統中執行緒實現的三種方式,忽然想起我以

    分頁的實現-不用額外請求

    情景:千里碼有些最優化題目的旁邊會有一個排行榜,用來展示不同的答案。比如[Uber打車匹配](http://www.qlcoder.com/task/7596) 這裡的答題人數並不多,但是[老王

    STM32F103按鍵操作的實現——狀態機

    #ifndef _KEY_H_ #define _KEY_H_ #include "HAL_gpio.h" // 換成STM32F103對應的GPIO庫 #include "type.h" // type.h主要是一些型別的重新命名 #define KEY_U

    java線性表的兩實現方式區別

    注意:線性表的兩種實現->順序實現和鏈式實現 線性表的兩種實現 順序表 連結串列 空間效能 順序表的儲存空間是靜態分佈的,需要一個固定的陣列,總有部分陣列元素要浪費 連結串列的儲存空間是動態分佈,因此不會有空間被浪費。但由於連結串列需要額外的空間來

    實現非阻塞網路通訊的方法———使用libev

    背景:最近終於開始了我的實習生之路,本來在進公司之前還比較緊張,儘管拿到了offer,因為畢竟這是一個新的起點,一開始從學生到員工這個身份的轉變讓我有些不太適應,但是還好在公司裡遇到了人超級好的軟體經理Alex以及其他精明能幹的小夥伴們,所以這個過渡時間也很快。 一開始Al

    Java阻塞佇列的幾實現方式

    1.wait()和notify()方式(摘自:https://segmentfault.com/a/1190000000373535) 阻塞佇列與普通佇列的區別在於,當佇列是空的時,從佇列中獲取元素的操作將會被阻塞,或者當佇列是滿時,往佇列裡新增元素的操作會被阻塞。試圖從

    嘗試新思路——CError的實現方式

    程式碼如下: #ifndef __MYERROR_H__ #define __MYERROR_H__ #include "Error.h" #include <map> #include

    Sticky Header的實現方法

    使用Sticky Header的list單個item一般情況下使用的資料結構是 {data:"what's inside", category:"section name"} 這樣儲存其實是浪費了很多的空間,因為category的名字被儲存的多次。在移動環境

    縮放到選中的實現

    Dim pDoc As IMxDocumentSet pDoc = ThisDocumentDim pMap As IMapSet pMap = pDoc.FocusMapDim pLayer As IFeatureLayerDim pFSel As IFeatureSele

    代理的實現方式

    代理相信大家都很熟悉了。不過還是說下吧。 舉個例子: // // A.h // Created by XX // @protocol SomeDelegate <NSObject> - (void)someMethod:(UIVi