少年阿賓

          那些青春的歲月

            BlogJava :: 首頁 :: 聯系 :: 聚合  :: 管理
            500 Posts :: 0 Stories :: 135 Comments :: 0 Trackbacks

          根據網上的資料做些整理

          Java NIO API詳解

          http://www.aygfsteel.com/19851985lili/articles/93524.html

          這篇文章對nio的api講解比較全,可以幫助在宏觀上把握nio。

          BIO 方式使得整個處理過程和連接是綁定的,只要連接建立,無論客戶端是否有消息發送,都要進行等待處理,一定程度上浪費了服務器端的硬件資源,因此就有了NIO 方式。Java 對于 NIO 方式的支持是通過 Channel和 Selector 方式來實現,采用的方法為向 Channel注冊感興趣的事件,然后通過 Selector 來獲取到發生了事件的 key,如發生了相應的事件,則進行相應的處理,否則則不做任何處理,是典型的Reactor 模式,按照這樣的方式,就不用像 BIO 方式一樣,即使在沒有消息的情況下也需要占據一個線程來阻塞讀取消息,從而提升服務器的使用效率, 為實現 TCP/IP+NIO 方式的系統間通訊, Java 提供了 SocketChannel和 ServerSocketChannel兩個關鍵的類,網絡 IO 的操作則改為通過ByteBuffer 來實現,具體的基于 java實現TCP/IP+NIO 方式的通訊的方法如下所示。

          服務器端:

          package com.flyoung;

          import java.io.IOException;
          import java.net.InetSocketAddress;
          import java.net.ServerSocket;
          import java.nio.ByteBuffer;
          import java.nio.channels.SelectionKey;
          import java.nio.channels.Selector;
          import java.nio.channels.ServerSocketChannel;
          import java.util.Iterator;
          import java.util.Set;
          import java.nio.channels.SocketChannel;

          public class NIOServer {
              
          /*標志數字*/
              
          private static int flag = 0;
              
          /*定義緩沖區大小*/
              
          private static int block = 4096;
              
          /*接收緩沖區*/
              
          private static ByteBuffer receiveBuffer = ByteBuffer.allocate(block);
              
          /*發送緩沖區*/
              
          private static ByteBuffer sendBuffer = ByteBuffer.allocate(block);
              
          /*定義Selector*/
              
          private Selector selector;
              
              
          public NIOServer(int port) throws IOException{
                  
          //打開服務器套接字通道
                  ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
                  
          //服務器配置為非阻塞
                  serverSocketChannel.configureBlocking(false);
                  
          //檢索與此服務器套接字通道關聯的套接字
                  ServerSocket serverSocket = serverSocketChannel.socket();
                  
          //進行服務的綁定
                  serverSocket.bind(new InetSocketAddress(port));
                  
          //通過open()方法找到Selector
                  selector = Selector.open();
                  
          //注冊到selector
                  serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
                  System.out.println(
          "Server Start -----8888:");
              }
              
          //監聽
              public void listen() throws IOException{
                  
          while(true){
                      
          //監控所有注冊的 channel ,當其中有注冊的 IO 操作可以進行時,該函數返回,并將對應的 SelectionKey 加入 selected-key set
                      selector.select();
                      
          //Selected-key set 代表了所有通過 select() 方法監測到可以進行 IO 操作的 channel ,這個集合可以通過 selectedKeys() 拿到
                      Set<SelectionKey> selectionKeys = selector.selectedKeys();
                      Iterator
          <SelectionKey> iterator = selectionKeys.iterator();
                      
          while(iterator.hasNext()){
                          SelectionKey selectionKey 
          = iterator.next();
                          handleKey(selectionKey);
                          iterator.remove();
                      }
                  }
                  
              }
              
          //處理請求
              public void handleKey(SelectionKey selectionKey) throws IOException{
                  
          //接受請求
                  ServerSocketChannel serverSocketChannel = null;
                  SocketChannel socketChannel 
          = null;
                  String receiveText;
                  String sendText;
                  
          int count;
                  
          //測試此鍵的通道是否準備好接受新的套接字連接
                  if(selectionKey.isAcceptable()){
                      
          //返回創建此鍵的通道
                      serverSocketChannel = (ServerSocketChannel)selectionKey.channel();
                      
          //接受客戶端建立連接的請求,并返回 SocketChannel 對象
                      socketChannel = serverSocketChannel.accept();
                      
          //配置為非阻塞
                      socketChannel.configureBlocking(false);
                      
          //注冊到selector
                      socketChannel.register(selector, SelectionKey.OP_READ);
                  }
          else if(selectionKey.isReadable()){
                      
          //返回為之創建此鍵的通道
                      socketChannel = (SocketChannel)selectionKey.channel();
                      
          //將緩沖區清空,以備下次讀取
                      receiveBuffer.clear();
                      
          //將發送來的數據讀取到緩沖區
                      
                      count 
          = socketChannel.read(receiveBuffer);
                  
                      
                      
          if(count>0){
                          receiveText 
          = new String(receiveBuffer.array(),0,count);
                          System.out.println(
          "服務器端接受到的數據---"+receiveText);
                          socketChannel.register(selector, SelectionKey.OP_WRITE);
                      }
                  }
          else if (selectionKey.isWritable()) {  
                      
          //將緩沖區清空以備下次寫入  
                      sendBuffer.clear();  
                      
          // 返回為之創建此鍵的通道。  
                      socketChannel = (SocketChannel) selectionKey.channel();  
                      sendText
          ="message from server--" + flag++;  
                      
          //向緩沖區中輸入數據  
                      sendBuffer.put(sendText.getBytes());  
                       
          //將緩沖區各標志復位,因為向里面put了數據標志被改變要想從中讀取數據發向服務器,就要復位  
                      sendBuffer.flip();  
                      
          //輸出到通道  
                      socketChannel.write(sendBuffer);  
                      System.out.println(
          "服務器端向客戶端發送數據--:"+sendText);  
                      socketChannel.register(selector, SelectionKey.OP_READ);  
                  }  
                  
              }
              
          public static void main(String[] args) throws IOException {
                  
          int port = 8888
                  NIOServer server 
          = new NIOServer(port);
                  server.listen();
              }

          }

           

          客戶端

          package com.flyoung;

          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.Set;

          public class NIOClient {
              
          /*標識數字*/  
              
          private static int flag = 0;  
              
          /*緩沖區大小*/  
              
          private static int BLOCK = 4096;  
              
          /*接受數據緩沖區*/  
              
          private static ByteBuffer sendBuffer = ByteBuffer.allocate(BLOCK);  
              
          /*發送數據緩沖區*/  
              
          private static ByteBuffer receiveBuffer = ByteBuffer.allocate(BLOCK);  
              
          /*服務器端地址*/  
              
          private final static InetSocketAddress SERVER_ADDRESS = new InetSocketAddress(  
                      
          "localhost"8888);  
            
              
          public static void main(String[] args) throws IOException {  
                  
          // 打開socket通道  
                  SocketChannel clientChannel = SocketChannel.open();  
                  
          // 設置為非阻塞方式  
                  clientChannel.configureBlocking(false);  
                  
          // 打開選擇器  
                  Selector selector = Selector.open();  
                  
          // 注冊連接服務端socket動作  
                  clientChannel.register(selector, SelectionKey.OP_CONNECT);  
                  
          // 連接  
                  clientChannel.connect(SERVER_ADDRESS);  
              
                  SocketChannel socketChannel;
                  Set
          <SelectionKey> selectionKeys;    
                  String receiveText;  
                  String sendText;  
                  
          int count=0;  
            
                  
          while (true) {  
                      
          //選擇一組鍵,其相應的通道已為 I/O 操作準備就緒。  
                      
          //監控所有注冊的 channel ,當其中有注冊的 IO 操作可以進行時,該函數返回,并將對應的 SelectionKey 加入 selected-key set 
                      selector.select();  
                      
          //返回此選擇器的已選擇鍵集。  
                      selectionKeys = selector.selectedKeys();  
                      
          //System.out.println(selectionKeys.size());  
                      for(SelectionKey selectionKey:selectionKeys){ 
                          
          //判斷是否為建立連接的事件
                          if (selectionKey.isConnectable()) {  
                              System.out.println(
          "client connect");  
                              socketChannel 
          = (SocketChannel) selectionKey.channel();  //
                              
          // 判斷此通道上是否正在進行連接操作。  
                              
          // 完成套接字通道的連接過程。  
                              if (socketChannel.isConnectionPending()) { 
                                  
          //完成連接的建立(TCP三次握手)
                                  socketChannel.finishConnect();  
                                  System.out.println(
          "完成連接!");  
                                  sendBuffer.clear();  
                                  sendBuffer.put(
          "Hello,Server".getBytes());  
                                  sendBuffer.flip();  
                                  socketChannel.write(sendBuffer);  
                              }  
                              socketChannel.register(selector, SelectionKey.OP_READ);  
                          } 
          else if (selectionKey.isReadable()) {  
                              socketChannel 
          = (SocketChannel) selectionKey.channel();  
                              
          //將緩沖區清空以備下次讀取  
                              receiveBuffer.clear();  
                              
          //讀取服務器發送來的數據到緩沖區中  
                              count=socketChannel.read(receiveBuffer);  
                              
          if(count>0){  
                                  receiveText 
          = new String( receiveBuffer.array(),0,count);  
                                  System.out.println(
          "客戶端接受服務器端數據--:"+receiveText);  
                                  socketChannel.register(selector, SelectionKey.OP_WRITE);  
                              }  
            
                          } 
          else if (selectionKey.isWritable()) {  
                              sendBuffer.clear();  
                              socketChannel 
          = (SocketChannel) selectionKey.channel();  
                              sendText 
          = "message from client--" + (flag++);  
                              sendBuffer.put(sendText.getBytes());  
                               
          //將緩沖區各標志復位,因為向里面put了數據標志被改變要想從中讀取數據發向服務器,就要復位  
                              sendBuffer.flip();  
                              socketChannel.write(sendBuffer);  
                              System.out.println(
          "客戶端向服務器端發送數據--:"+sendText);  
                              socketChannel.register(selector, SelectionKey.OP_READ);  
                          }  
                      }  
                      selectionKeys.clear();  
                  }  
              }  
          }




          posted on 2012-08-09 12:59 abin 閱讀(648) 評論(0)  編輯  收藏

          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 来安县| 平山县| 根河市| 灵宝市| 荔浦县| 德兴市| 焉耆| 封开县| 深泽县| 石门县| 页游| 得荣县| 河东区| 仪征市| 南京市| 大名县| 涿州市| 扬中市| 木兰县| 偏关县| 鲜城| 瓮安县| 临邑县| 河曲县| 西乌| 晋宁县| 长乐市| 朝阳区| 晴隆县| 肇东市| 库车县| 崇义县| 新营市| 蓬莱市| 呼图壁县| 上虞市| 东兴市| 江孜县| 巴彦县| 兴化市| 灵宝市|