程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> Java NIO道理圖文剖析及代碼完成

Java NIO道理圖文剖析及代碼完成

編輯:關於JAVA

Java NIO道理圖文剖析及代碼完成。本站提示廣大學習愛好者:(Java NIO道理圖文剖析及代碼完成)文章只能為提供參考,不一定能成為您想要的結果。以下是Java NIO道理圖文剖析及代碼完成正文


媒介:

比來在剖析hadoop的RPC(Remote Procedure Call Protocol ,長途進程挪用協定,它是一種經由過程收集從長途盤算機法式上要求辦事,而不須要懂得底層收集技巧的協定。可以參考:http://baike.百度.com/view/32726.htm )機制時,發明hadoop的RPC機制的完成重要用到了兩個技巧:靜態署理(靜態署理可以參考博客:http://weixiaolu.iteye.com/blog/1477774 )和java NIO。為了可以或許准確地剖析hadoop的RPC源碼,我認為很有需要先研討一下java NIO的道理和詳細完成。

這篇博客我重要從兩個偏向來剖析java NIO

目次:

一.java NIO 和壅塞I/O的差別
     1. 壅塞I/O通訊模子
     2. java NIO道理及通訊模子
二.java NIO辦事端和客戶端代碼完成

詳細剖析:

一.java NIO 和壅塞I/O的差別

1. 壅塞I/O通訊模子

假設如今你對壅塞I/O已有了必定懂得,我們曉得壅塞I/O在挪用InputStream.read()辦法時是壅塞的,它會一向比及數據到來時(或超時)才會前往;異樣,在挪用ServerSocket.accept()辦法時,也會一向壅塞到有客戶端銜接才會前往,每一個客戶端銜接過去後,辦事端都邑啟動一個線程行止理該客戶真個要求。壅塞I/O的通訊模子表示圖以下:


 

 假如你細細剖析,必定會發明壅塞I/O存在一些缺陷。依據壅塞I/O通訊模子,我總結了它的兩點缺陷:

1. 當客戶端多時,會創立年夜量的處置線程。且每一個線程都要占用棧空間和一些CPU時光

2. 壅塞能夠帶來頻仍的高低文切換,且年夜部門高低文切換能夠是有意義的。

在這類情形下非壅塞式I/O就有了它的運用遠景。

2. java NIO道理及通訊模子

Java NIO是在jdk1.4開端應用的,它既可以說成“新I/O”,也能夠說成非壅塞式I/O。上面是java NIO的任務道理:

1. 由一個專門的線程來處置一切的 IO 事宜,並擔任分發。
2. 事宜驅念頭制:事宜到的時刻觸發,而不是同步的去監督事宜。
3. 線程通信:線程之間經由過程 wait,notify 等方法通信。包管每次高低文切換都是成心義的。削減無謂的線程切換。

浏覽過一些材料以後,上面貼出我懂得的java NIO的任務道理圖:

 
(注:每一個線程的處置流程年夜概都是讀取數據、解碼、盤算處置、編碼、發送呼應。)

Java NIO的辦事端只需啟動一個專門的線程來處置一切的 IO 事宜,這類通訊模子是怎樣完成的呢?呵呵,我們一路來探討它的奧妙吧。java NIO采取了雙向通道(channel)停止數據傳輸,而不是單向的流(stream),在通道上可以注冊我們感興致的事宜。一共有以下四種事宜:


事宜名 對應值 辦事端吸收客戶端銜接事宜 SelectionKey.OP_ACCEPT(16) 客戶端銜接辦事端事宜 SelectionKey.OP_CONNECT(8) 讀事宜 SelectionKey.OP_READ(1) 寫事宜 SelectionKey.OP_WRITE(4)         

  辦事端和客戶端各自保護一個治理通道的對象,我們稱之為selector,該對象能檢測一個或多個通道 (channel) 上的事宜。我們以辦事端為例,假如辦事真個selector上注冊了讀事宜,某時辰客戶端給辦事端發送了一些數據,壅塞I/O這時候會挪用read()辦法壅塞地讀取數據,而NIO的辦事端會在selector中添加一個讀事宜。辦事真個處置線程會輪詢地拜訪selector,假如拜訪selector時發明有感興致的事宜達到,則處置這些事宜,假如沒有感興致的事宜達到,則處置線程會一向壅塞直到感興致的事宜達到為止。上面是我懂得的java NIO的通訊模子表示圖:


 

 二.java NIO辦事端和客戶端代碼完成

為了更好地輿解java NIO,上面貼出辦事端和客戶真個簡略代碼完成。

辦事端:

package cn.nio; 
 
import java.io.IOException; 
import java.net.InetSocketAddress; 
import java.nio.ByteBuffer; 
import java.nio.channels.SelectionKey; 
import java.nio.channels.Selector; 
import java.nio.channels.ServerSocketChannel; 
import java.nio.channels.SocketChannel; 
import java.util.Iterator; 
 
/** 
 * NIO辦事端 
 * @author 巷子 
 */ 
public class NIOServer { 
 //通道治理器 
 private Selector selector; 
 
 /** 
  * 取得一個ServerSocket通道,並對該通道做一些初始化的任務 
  * @param port 綁定的端標語 
  * @throws IOException 
  */ 
 public void initServer(int port) throws IOException { 
  // 取得一個ServerSocket通道 
  ServerSocketChannel serverChannel = ServerSocketChannel.open(); 
  // 設置通道為非壅塞 
  serverChannel.configureBlocking(false); 
  // 將該通道對應的ServerSocket綁定到port端口 
  serverChannel.socket().bind(new InetSocketAddress(port)); 
  // 取得一個通道治理器 
  this.selector = Selector.open(); 
  //將通道治理器和該通道綁定,並為該通道注冊SelectionKey.OP_ACCEPT事宜,注冊該事宜後, 
  //當該事宜達到時,selector.select()會前往,假如該事宜沒達到selector.select()會一向壅塞。 
  serverChannel.register(selector, SelectionKey.OP_ACCEPT); 
 } 
 
 /** 
  * 采取輪詢的方法監聽selector上能否有須要處置的事宜,假如有,則停止處置 
  * @throws IOException 
  */ 
 @SuppressWarnings("unchecked") 
 public void listen() throws IOException { 
  System.out.println("辦事端啟動勝利!"); 
  // 輪詢拜訪selector 
  while (true) { 
   //當注冊的事宜達到時,辦法前往;不然,該辦法會一向壅塞 
   selector.select(); 
   // 取得selector當選中的項的迭代器,選中的項為注冊的事宜 
   Iterator ite = this.selector.selectedKeys().iterator(); 
   while (ite.hasNext()) { 
    SelectionKey key = (SelectionKey) ite.next(); 
    // 刪除已選的key,以防反復處置 
    ite.remove(); 
    // 客戶端要求銜接事宜 
    if (key.isAcceptable()) { 
     ServerSocketChannel server = (ServerSocketChannel) key 
       .channel(); 
     // 取得和客戶端銜接的通道 
     SocketChannel channel = server.accept(); 
     // 設置成非壅塞 
     channel.configureBlocking(false); 
 
     //在這裡可以給客戶端發送信息哦 
     channel.write(ByteBuffer.wrap(new String("向客戶端發送了一條信息").getBytes())); 
     //在和客戶端銜接勝利以後,為了可以吸收到客戶真個信息,須要給通道設置讀的權限。 
     channel.register(this.selector, SelectionKey.OP_READ); 
      
     // 取得了可讀的事宜 
    } else if (key.isReadable()) { 
      read(key); 
    } 
 
   } 
 
  } 
 } 
 /** 
  * 處置讀取客戶端發來的信息 的事宜 
  * @param key 
  * @throws IOException 
  */ 
 public void read(SelectionKey key) throws IOException{ 
  // 辦事器可讀撤消息:獲得事宜產生的Socket通道 
  SocketChannel channel = (SocketChannel) key.channel(); 
  // 創立讀取的緩沖區 
  ByteBuffer buffer = ByteBuffer.allocate(10); 
  channel.read(buffer); 
  byte[] data = buffer.array(); 
  String msg = new String(data).trim(); 
  System.out.println("辦事端收到信息:"+msg); 
  ByteBuffer outBuffer = ByteBuffer.wrap(msg.getBytes()); 
  channel.write(outBuffer);// 將新聞回送給客戶端 
 } 
  
 /** 
  * 啟動辦事端測試 
  * @throws IOException 
  */ 
 public static void main(String[] args) throws IOException { 
  NIOServer server = new NIOServer(); 
  server.initServer(8000); 
  server.listen(); 
 } 
 
} 
 
 
 

客戶端:

package cn.nio; 
 
import java.io.IOException; 
import java.net.InetSocketAddress; 
import java.nio.ByteBuffer; 
import java.nio.channels.SelectionKey; 
import java.nio.channels.Selector; 
import java.nio.channels.SocketChannel; 
import java.util.Iterator; 
 
/** 
 * NIO客戶端 
 * @author 巷子 
 */ 
public class NIOClient { 
 //通道治理器 
 private Selector selector; 
 
 /** 
  * 取得一個Socket通道,並對該通道做一些初始化的任務 
  * @param ip 銜接的辦事器的ip 
  * @param port 銜接的辦事器的端標語   
  * @throws IOException 
  */ 
 public void initClient(String ip,int port) throws IOException { 
  // 取得一個Socket通道 
  SocketChannel channel = SocketChannel.open(); 
  // 設置通道為非壅塞 
  channel.configureBlocking(false); 
  // 取得一個通道治理器 
  this.selector = Selector.open(); 
   
  // 客戶端銜接辦事器,其實辦法履行並沒有完成銜接,須要在listen()辦法中調 
  //用channel.finishConnect();能力完成銜接 
  channel.connect(new InetSocketAddress(ip,port)); 
  //將通道治理器和該通道綁定,並為該通道注冊SelectionKey.OP_CONNECT事宜。 
  channel.register(selector, SelectionKey.OP_CONNECT); 
 } 
 
 /** 
  * 采取輪詢的方法監聽selector上能否有須要處置的事宜,假如有,則停止處置 
  * @throws IOException 
  */ 
 @SuppressWarnings("unchecked") 
 public void listen() throws IOException { 
  // 輪詢拜訪selector 
  while (true) { 
   selector.select(); 
   // 取得selector當選中的項的迭代器 
   Iterator ite = this.selector.selectedKeys().iterator(); 
   while (ite.hasNext()) { 
    SelectionKey key = (SelectionKey) ite.next(); 
    // 刪除已選的key,以防反復處置 
    ite.remove(); 
    // 銜接事宜產生 
    if (key.isConnectable()) { 
     SocketChannel channel = (SocketChannel) key 
       .channel(); 
     // 假如正在銜接,則完成銜接 
     if(channel.isConnectionPending()){ 
      channel.finishConnect(); 
       
     } 
     // 設置成非壅塞 
     channel.configureBlocking(false); 
 
     //在這裡可以給辦事端發送信息哦 
     channel.write(ByteBuffer.wrap(new String("向辦事端發送了一條信息").getBytes())); 
     //在和辦事端銜接勝利以後,為了可以吸收到辦事真個信息,須要給通道設置讀的權限。 
     channel.register(this.selector, SelectionKey.OP_READ); 
      
     // 取得了可讀的事宜 
    } else if (key.isReadable()) { 
      read(key); 
    } 
 
   } 
 
  } 
 } 
 /** 
  * 處置讀取辦事端發來的信息 的事宜 
  * @param key 
  * @throws IOException 
  */ 
 public void read(SelectionKey key) throws IOException{ 
  //和辦事真個read辦法一樣 
 } 
  
  
 /** 
  * 啟動客戶端測試 
  * @throws IOException 
  */ 
 public static void main(String[] args) throws IOException { 
  NIOClient client = new NIOClient(); 
  client.initClient("localhost",8000); 
  client.listen(); 
 } 
 
} 
 

小結:

終究把靜態署理和java NIO剖析完了,呵呵,上面就要剖析hadoop的RPC機制源碼了,博客地址:http://weixiaolu.iteye.com/blog/1504898 。不外假如對java NIO的懂得存在貳言的,迎接一路評論辯論。
如需轉載,請注明出處:http://weixiaolu.iteye.com/blog/1479656

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved