NIO Socket非阻塞模式

NIO主要原理和適用算法

NIO 有一個主要的類Selector,這個相似一個觀察者,只要咱們把須要探知的socketchannel告訴Selector,咱們接着作別的事情,當有 事件發生時,他會通知咱們,傳回一組SelectionKey,咱們讀取這些Key,就會得到咱們剛剛註冊過的socketchannel,而後,咱們從 這個Channel中讀取數據,放心,包準可以讀到,接着咱們能夠處理這些數據。數據庫

Selector內部原理實際是在作一個對所註冊的channel的輪詢訪問,不斷的輪詢(目前就這一個算法),一旦輪詢到一個channel有所註冊的事情發生,好比數據來了,他就會站起來報告,交出一把鑰匙,讓咱們經過這把鑰匙來讀取這個channel的內容。服務器

jdk供的無阻塞I/O(NIO)有效解決了多線程服務器存在的線程開銷問題,但在使用上略顯得複雜一些。在NIO中使用多線程,主要目的已不是爲了應對 每一個客戶端請求而分配獨立的服務線程,而是經過多線程充分使用用多個CPU的處理能力和處理中的等待時間,達到提升服務能力的目的。多線程

這段時間在研究NIO,寫篇博客來記住學過的東西。仍是從最簡單的Hello World開始,client多線程請求server端,server接收client的名字,並返回Hello! +名字的字符格式給client。固然實際應用並不這麼簡單,實際多是訪問文件或者數據庫獲取信息返回給client。非阻塞的NIO有何神祕之處?socket

代 碼:this

1)server端代碼spa

  1. public class HelloWorldServer {   
  2.  
  3.     static int BLOCK = 1024;   
  4.     static String name = "";   
  5.     protected Selector selector;   
  6.     protected ByteBuffer clientBuffer = ByteBuffer.allocate(BLOCK);   
  7.     protected CharsetDecoder decoder;   
  8.     static CharsetEncoder encoder = Charset.forName("GB2312").newEncoder();   
  9.  
  10.     public HelloWorldServer(int port) throws IOException {   
  11.         selector = this.getSelector(port);   
  12.         Charset charset = Charset.forName("GB2312");   
  13.         decoder = charset.newDecoder();   
  14.     }   
  15.  
  16.     // 獲取Selector   
  17.     protected Selector getSelector(int port) throws IOException {   
  18.         ServerSocketChannel server = ServerSocketChannel.open();   
  19.         Selector sel = Selector.open();   
  20.         server.socket().bind(new InetSocketAddress(port));   
  21.         server.configureBlocking(false);   
  22.         server.register(sel, SelectionKey.OP_ACCEPT);   
  23.         return sel;   
  24.     }   
  25.  
  26.     // 監聽端口   
  27.     public void listen() {   
  28.         try {   
  29.             for (;;) {   
  30.                 selector.select();   
  31.                 Iterator iter = selector.selectedKeys().iterator();   
  32.                 while (iter.hasNext()) {   
  33.                     SelectionKey key = (SelectionKey) iter.next();   
  34.                     iter.remove();   
  35.                     process(key);   
  36.                 }   
  37.             }   
  38.         } catch (IOException e) {   
  39.             e.printStackTrace();   
  40.         }   
  41.     }   
  42.  
  43.     // 處理事件   
  44.     protected void process(SelectionKey key) throws IOException {   
  45.         if (key.isAcceptable()) { // 接收請求   
  46.             ServerSocketChannel server = (ServerSocketChannel) key.channel();   
  47.             SocketChannel channel = server.accept();   
  48.             //設置非阻塞模式   
  49.             channel.configureBlocking(false);   
  50.             channel.register(selector, SelectionKey.OP_READ);   
  51.         } else if (key.isReadable()) { // 讀信息   
  52.             SocketChannel channel = (SocketChannel) key.channel();   
  53.             int count = channel.read(clientBuffer);   
  54.             if (count > 0) {   
  55.                 clientBuffer.flip();   
  56.                 CharBuffer charBuffer = decoder.decode(clientBuffer);   
  57.                 name = charBuffer.toString();   
  58.                 // System.out.println(name);   
  59.                 SelectionKey sKey = channel.register(selector,   
  60.                         SelectionKey.OP_WRITE);   
  61.                 sKey.attach(name);   
  62.             } else {   
  63.                 channel.close();   
  64.             }   
  65.  
  66.             clientBuffer.clear();   
  67.         } else if (key.isWritable()) { // 寫事件   
  68.             SocketChannel channel = (SocketChannel) key.channel();   
  69.             String name = (String) key.attachment();   
  70.                
  71.             ByteBuffer block = encoder.encode(CharBuffer   
  72.                     .wrap("Hello !" + name));   
  73.                
  74.  
  75.             channel.write(block);   
  76.  
  77.             //channel.close();   
  78.  
  79.         }   
  80.     }   
  81.  
  82.     public static void main(String[] args) {   
  83.         int port = 8888;   
  84.         try {   
  85.             HelloWorldServer server = new HelloWorldServer(port);   
  86.             System.out.println("listening on " + port);   
  87.                
  88.             server.listen();   
  89.                
  90.         } catch (IOException e) {   
  91.             e.printStackTrace();   
  92.         }   
  93.     }   
  94. }  

2)client端代碼線程

  1. public class HelloWorldClient {   
  2.  
  3.     static int SIZE = 10;   
  4.     static InetSocketAddress ip = new InetSocketAddress("localhost", 8888);   
  5.     static CharsetEncoder encoder = Charset.forName("GB2312").newEncoder();   
  6.  
  7.     static class Message implements Runnable {   
  8.         protected String name;   
  9.         String msg = "";   
  10.  
  11.         public Message(String index) {   
  12.             this.name = index;   
  13.         }   
  14.  
  15.         public void run() {   
  16.             try {   
  17.                 long start = System.currentTimeMillis();   
  18.                 //打開Socket通道   
  19.                 SocketChannel client = SocketChannel.open();   
  20.                 //設置爲非阻塞模式   
  21.                 client.configureBlocking(false);   
  22.                 //打開選擇器   
  23.                 Selector selector = Selector.open();   
  24.                 //註冊鏈接服務端socket動做   
  25.                 client.register(selector, SelectionKey.OP_CONNECT);   
  26.                 //鏈接   
  27.                 client.connect(ip);   
  28.                 //分配內存   
  29.                 ByteBuffer buffer = ByteBuffer.allocate(8 * 1024);   
  30.                 int total = 0;   
  31.  
  32.                 _FOR: for (;;) {   
  33.                     selector.select();   
  34.                     Iterator iter = selector.selectedKeys().iterator();   
  35.  
  36.                     while (iter.hasNext()) {   
  37.                         SelectionKey key = (SelectionKey) iter.next();   
  38.                         iter.remove();   
  39.                         if (key.isConnectable()) {   
  40.                             SocketChannel channel = (SocketChannel) key   
  41.                                     .channel();   
  42.                             if (channel.isConnectionPending())   
  43.                                 channel.finishConnect();   
  44.                             channel   
  45.                                     .write(encoder   
  46.                                             .encode(CharBuffer.wrap(name)));   
  47.  
  48.                             channel.register(selector, SelectionKey.OP_READ);   
  49.                         } else if (key.isReadable()) {   
  50.                             SocketChannel channel = (SocketChannel) key   
  51.                                     .channel();   
  52.                             int count = channel.read(buffer);   
  53.                             if (count > 0) {   
  54.                                 total += count;   
  55.                                 buffer.flip();   
  56.  
  57.                                 while (buffer.remaining() > 0) {   
  58.                                     byte b = buffer.get();   
  59.                                     msg += (char) b;   
  60.                                        
  61.                                 }   
  62.  
  63.                                 buffer.clear();   
  64.                             } else {   
  65.                                 client.close();   
  66.                                 break _FOR;   
  67.                             }   
  68.                         }   
  69.                     }   
  70.                 }   
  71.                 double last = (System.currentTimeMillis() - start) * 1.0 / 1000;   
  72.                 System.out.println(msg + "used time :" + last + "s.");   
  73.                 msg = "";   
  74.             } catch (IOException e) {   
  75.                 e.printStackTrace();   
  76.             }   
  77.         }   
  78.     }   
  79.  
  80.     public static void main(String[] args) throws IOException {   
  81.        
  82.         String names[] = new String[SIZE];   
  83.  
  84.         for (int index = 0; index < SIZE; index++) {   
  85.             names[index] = "jeff[" + index + "]";   
  86.             new Thread(new Message(names[index])).start();   
  87.         }   
  88.        
  89.     }   
  90. }  
相關文章
相關標籤/搜索