小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

非阻塞通信

 windli筆記 2011-09-15
對于用ServerSocket和Socket寫的服務器程序或著客戶端程序,在運行的時候常常會阻塞,如當一個線程執(zhí)行ServerSocket的accept()方法,如果沒有客戶機連接,該線程就會一直阻塞直到有了客戶機連接才從accept()方法返回,再如,當線程執(zhí)行Socket的read()方法,如果輸入流中沒有數(shù)據(jù),該線程就會一直等到有數(shù)據(jù)可讀時才從read()方法返回。

    如果服務器要與多個客戶機通信,通常做法為每個客戶機連接開啟一個服務線程,每個工作線程都有可能經(jīng)常處于長時間的阻塞狀態(tài)。

    從JDK1.4版本開始,引入了非阻塞的通信機制。服務器程序接收客戶連接、客戶程序建立與服務器的連接,以及服務器程序和客戶程序收發(fā)數(shù)據(jù)的操作都可以按非阻塞的方式進行。服務器程序只需要創(chuàng)建一個線程,就能完成同時與多個客戶通信的任務。

    非阻塞通信要比傳統(tǒng)的阻塞方式效率要高,Apache的MIMA框架就是以java.nio包中的類編寫的。

    不知道是否有朋友看過 孫衛(wèi)琴寫的《Java網(wǎng)絡編程精解》,在提到線程阻塞的時

Java網(wǎng)絡編程精解 第84頁 寫道
線程從Socket的輸入流讀入數(shù)據(jù)時,如果沒有足夠的數(shù)據(jù),就會進入阻塞狀態(tài),直到讀到了足夠的數(shù)據(jù),或者到達輸入流的未尾,或者出現(xiàn)了異常,才從輸入流的read()方法返回或異常中斷。輸入流中有多少數(shù)據(jù)才算足夠呢,這要看線程執(zhí)行read方法的類型。
    int read():只要輸入有一個字節(jié),就算足夠。
    int read(byte[] buff):只要輸入流中的字節(jié)數(shù)目與參數(shù)buff數(shù)組的長度相同,就算足夠。

 我對描紅的描述持不同的意見

  byte[] msgBytes = new byte[512];
  inputStream.read(msgBytes); 

如果按書中描述,這行代碼必須讀到512個字節(jié)后才從阻塞狀態(tài)中返回,如果沒有讀到足夠的512個字節(jié),則一直阻塞。但實際情況卻不是這樣的,只要流里哪怕只有一個字節(jié) ,inputStream.read(msgBytes)也會立即返回,返回值為讀到的字節(jié)數(shù)。

下面是簡單的NIO示例

1、服務端程序,非阻塞方式

Java代碼 復制代碼 收藏代碼
  1. package com.bill99.nioserver;   
  2.   
  3. import java.io.IOException;   
  4. import java.net.InetSocketAddress;   
  5. import java.nio.ByteBuffer;   
  6. import java.nio.channels.SelectionKey;   
  7. import java.nio.channels.Selector;   
  8. import java.nio.channels.ServerSocketChannel;   
  9. import java.nio.channels.SocketChannel;   
  10. import java.nio.channels.spi.SelectorProvider;   
  11. import java.nio.charset.Charset;   
  12. import java.util.Iterator;   
  13.   
  14. public class NIOServer {   
  15.     private Selector socketSelector = null;   
  16.     private ServerSocketChannel ssChannel = null;   
  17.     private SocketChannel socketChannel =null;   
  18.     private static SelectionKey key = null;   
  19.     private int port =5512;   
  20.     private int backlog = 100;   
  21.     private Charset charset = Charset.defaultCharset();   
  22.     private ByteBuffer shareBuffer = ByteBuffer.allocate(1024);//生成1kb的緩沖區(qū),可以根據(jù)實際情況調的更大些   
  23.        
  24.     public NIOServer()  {   
  25.         try {   
  26.             socketSelector = SelectorProvider.provider().openSelector();   
  27.             ssChannel =ServerSocketChannel.open() ;   
  28.             ssChannel.socket().bind(new InetSocketAddress(port),100);   
  29.             System.out.println(String.format("NIO服務器啟動,監(jiān)聽端口%1$s,最大連接數(shù)%2$s", port,backlog));   
  30.         } catch(IOException e){   
  31.             throw new ExceptionInInitializerError(e);   
  32.         }   
  33.     }   
  34.     /**  
  35.      * 接收客戶端連接  
  36.      */  
  37.     public void acceptConnect() {   
  38.         while(true) {   
  39.             try {   
  40.                 SocketChannel socketChannel = ssChannel.accept();//阻塞模式,直到有連接進入   
  41.                 System.out.println("收到客戶機連接,來自:"+ssChannel.socket().getInetAddress());   
  42.                 socketChannel.configureBlocking(false);//設置非阻塞模式   
  43.                 synchronized(this){   
  44.                     socketSelector.wakeup();   
  45.                     socketChannel.register(socketSelector,SelectionKey.OP_READ|   
  46.                                                           SelectionKey.OP_WRITE);   
  47.                 }   
  48.             } catch(IOException e){e.printStackTrace();}   
  49.         }   
  50.     }   
  51.     /**  
  52.      * 讀寫服務  
  53.      * @throws IOException  
  54.      */  
  55.     public void service() throws IOException{   
  56.         while (true) {   
  57.             synchronized (this) {//空的同步塊,目的是為了避免死鎖   
  58.             }   
  59.             if (!(socketSelector.select() > 0)) {   
  60.                 continue;   
  61.             }   
  62.             Iterator<SelectionKey> it = socketSelector.selectedKeys().iterator();   
  63.             while (it.hasNext()) {   
  64.                 key = it.next();   
  65.                 it.remove();   
  66.                 if(key.isReadable()) {// 讀就緒   
  67.                     this.readDataFromSocket(key);   
  68.                 }   
  69.                 if(key.isWritable()){//寫就緒   
  70.                     this.sayWelcome(key);   
  71.                 }   
  72.             }   
  73.         }   
  74.     }   
  75.     //讀取客戶機發(fā)來的數(shù)據(jù)   
  76.     private void readDataFromSocket(SelectionKey key) throws IOException {   
  77.         shareBuffer.clear();//清空buffer   
  78.         socketChannel=(SocketChannel) key.channel();   
  79.         int num=0;   
  80.         while((num = socketChannel.read(shareBuffer))>0){   
  81.             shareBuffer.flip();//將當前極限設置為位置,并把設置后的位置改為0   
  82.         }   
  83.         if(num ==-1){//讀取流的未尾,對方已關閉流   
  84.             socketChannel.close();   
  85.             return;   
  86.         }   
  87.         System.out.println("client request:"+charset.decode(shareBuffer).toString());   
  88.     }    
  89.     //向客戶機發(fā)響應信息   
  90.     private void sayWelcome(SelectionKey key) throws IOException {   
  91.         shareBuffer.clear();//清空buffer   
  92.         socketChannel=(SocketChannel) key.channel();   
  93.         shareBuffer.put("Welcome to china!this is a greate and very beautifual country!\n".getBytes());   
  94.         shareBuffer.flip();//將當前極限設置為位置,并把設置后的位置改為0   
  95.         socketChannel.write(shareBuffer);   
  96.     }   
  97.     //Main方法   
  98.     public static void main(String[] args) {   
  99.         final NIOServer server = new NIOServer();   
  100.         Runnable task = new  Runnable() {   
  101.             public void run() {   
  102.                 server.acceptConnect();   
  103.             }   
  104.         };   
  105.         new Thread(task).start();//啟動處理客戶機連接的線程   
  106.         try {   
  107.             server.service();   
  108.         } catch (IOException e) {//發(fā)生IO流異常時,關閉對應的socket   
  109.             try {   
  110.                 key.channel().close();   
  111.                 key.cancel();   
  112.             } catch (IOException e1) {   
  113.                 e1.printStackTrace();   
  114.             }   
  115.         }   
  116.     }   
  117. }  

 2、客戶端程序,阻塞方式

Java代碼 復制代碼 收藏代碼
  1. package com.bill99.client;   
  2.   
  3. import java.io.IOException;   
  4. import java.io.InputStream;   
  5. import java.io.OutputStream;   
  6. import java.net.Socket;   
  7. import java.nio.CharBuffer;   
  8.   
  9. import javax.net.SocketFactory;   
  10. //測試類   
  11. public class BlockingClient {   
  12.     private Socket socket = null;   
  13.     private OutputStream out = null;   
  14.     private InputStream in = null;   
  15.        
  16.     public BlockingClient() {   
  17.         try {   
  18.             socket= SocketFactory.getDefault().createSocket("127.0.0.1"5512);   
  19.             out = socket.getOutputStream();   
  20.             in = socket.getInputStream();   
  21.         } catch (IOException e) {   
  22.             e.printStackTrace();   
  23.         }   
  24.     }   
  25.     //發(fā)送請求并接收應答   
  26.     public String receiveRespMsg(String reqMsg) throws IOException{   
  27.         out.write(reqMsg.getBytes());   
  28.         out.flush();   
  29.         in = socket.getInputStream();   
  30.         int c =0;   
  31.         CharBuffer buffer = CharBuffer.allocate(1024);   
  32.         while((c=in.read())!=-1 && c!=10){   
  33.             buffer.put((char)c);   
  34.         }   
  35.         return new String(buffer.array()).trim();   
  36.     }   
  37.        
  38.     public static void main(String[] args) throws Exception{   
  39.         BlockingClient client = new BlockingClient();   
  40.         System.out.println("服務器響應:"+client.receiveRespMsg("hello\n"));   
  41.     }   
  42. }  

 

    總體而信,阻塞模式和非阻塞模式都可以同時處理多個客戶機的連接,但阻塞模式需要較多的線程許多時間都浪費在阻塞I/O操作上,Java虛擬機需要頻繁地轉讓CPU的使用權,而非阻塞模式只需要少量線程即可完成所有任務,非阻塞模式能更有效的利用CPU,系統(tǒng)開銷小,能夠提高程序的并發(fā)性能。

    本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內容均由用戶發(fā)布,不代表本站觀點。請注意甄別內容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權內容,請點擊一鍵舉報。
    轉藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多