使用Java NIO提高服務端程式的效能

來源:互聯網
上載者:User

  Java NIO增加了新的SocketChannel、ServerSocketChannel等類來提供對構建高效能的服務端程式的支援。 SocketChannel、ServerSocketChannel能夠在非阻塞的模式下工作,它們都是selectable的類。在構建伺服器或者中介軟體時,推薦使用Java NIO。

    在傳統的網路編程中,我們通常使用一個專用線程(Thread)來處理一個Socket串連,通過使用NIO,一個或者很少幾個Socket線程就可以處理成千上萬個活動的Socket串連。

    通常情況下,通過ServerSocketChannel.open()獲得一個ServerSocketChannel的執行個體,通過SocketChannel.open或者serverSocketChannel.accept()獲得一個SocketChannel執行個體。要使ServerSocketChannel或者SocketChannel在非阻塞的模式下操作,可以調用
    serverSocketChannel.configureBlocking (false);
    或者
    socketChannel.configureBlocking (false);

    語句來達到目的。通常情況下,服務端可以使用非阻塞的ServerSocketChannel,這樣,服務端的程式就可以更容易地同時處理多個socket線程。

    下面我們來看一個綜合例子,這個例子使用了ServerSocketChannel、SocketChannel開發了一個非阻塞的、能處理多線程的Echo服務端程式,見樣本12-14。
    【程式原始碼】

1 // ==================== Program Discription =====================2 // 程式名稱:樣本12-14 : SocketChannelDemo.java3 // 程式目的:學習Java NIO#SocketChannel4 // ==============================================================5 6 7 import java.nio.ByteBuffer;8 import java.nio.channels.ServerSocketChannel;9 import java.nio.channels.SocketChannel;10 import java.nio.channels.Selector;11 import java.nio.channels.SelectionKey;12 import java.nio.channels.SelectableChannel;13 14 import java.net.Socket;15 import java.net.ServerSocket;16 import java.net.InetSocketAddress;17 import java.util.Iterator;1819 public class SocketChannelDemo 20 21 {22  public static int PORT_NUMBER = 23;//監聽連接埠23  ServerSocketChannel serverChannel;24  ServerSocket serverSocket ;25  Selector selector ;26  private ByteBuffer buffer = ByteBuffer.allocateDirect (1024);27 28  public static void main (String [] args)29   throws Exception30  {31   SocketChannelDemo server=new SocketChannelDemo();32   server.init(args);33   server.startWork();34  }35 36 37  public void init (String [] argv)throws Exception38  {39   int port = PORT_NUMBER;40 41   if (argv.length > 0) { 42    port = Integer.parseInt (argv [0]);43   }44 45   System.out.println ("Listening on port " + port);46 47   // 分配一個ServerSocketChannel48   serverChannel = ServerSocketChannel.open();49   // 從ServerSocketChannel裡獲得一個對應的Socket50   serverSocket = serverChannel.socket();51   // 產生一個Selector52   selector = Selector.open();53 54   // 把Socket綁定到連接埠上55   serverSocket.bind (new InetSocketAddress (port));56   //serverChannel為非bolck57   serverChannel.configureBlocking (false);58 59   // 通過Selector註冊ServerSocetChannel60   serverChannel.register (selector, SelectionKey.OP_ACCEPT); 61   62  }63 64     public void startWork()throws Exception 65 66     {67      while (true) {68    69    int n = selector.select();//獲得IO準備就緒的channel數量70 71    if (n == 0) {72     continue; // 沒有channel準備就緒,繼續執行73    }74 75    // 用一個iterator返回Selector的selectedkeys76    Iterator it = selector.selectedKeys().iterator();77 78    // 處理每一個SelectionKey79    while (it.hasNext()) {80     SelectionKey key = (SelectionKey) it.next();8182     // 判斷是否有新的串連到達83 if (key.isAcceptable()) {84           //返回SelectionKey的ServerSocketChannel85      ServerSocketChannel server =(ServerSocketChannel) key.channel();86      SocketChannel channel = server.accept();87 88      registerChannel (selector, channel,89       SelectionKey.OP_READ);90 91      doWork (channel);92     }93 94     // 判斷是否有資料在此channel裡需要讀取95     if (key.isReadable()) {96        97      processData (key);98 99     }100 101     //刪除 selectedkeys102     it.remove();103    }104   }105  }106  protected void registerChannel (Selector selector,107   SelectableChannel channel, int ops)108   throws Exception109  { 110   if (channel == null) {111    return;  112   }113 114  115   channel.configureBlocking (false);116 117   channel.register (selector, ops);118  }119 120     //處理接收的資料121  protected void processData (SelectionKey key)122   throws Exception123  {124   125  126   SocketChannel socketChannel = (SocketChannel) key.channel();127   int count;128 129   buffer.clear();   // 清空buffer130 131   // 讀取所有的資料132   while ((count = socketChannel.read (buffer)) > 0) {133    buffer.flip();  134135    // send the data, don't assume it goes all at once136    while (buffer.hasRemaining())137    {138     //如果收到斷行符號鍵,則在返回的字元前增加[echo]$字樣139     if(buffer.get()==(char)13)140     {141      buffer.clear();142      buffer.put("[echo]$".getBytes());143      buffer.flip();144      145     }146     socketChannel.write (buffer);//在Socket裡寫資料147    }148   149    buffer.clear();  // 清空buffer150   }151 152   if (count < 0) {153    // count<0,說明已經讀取完畢154    socketChannel.close(); 155   }156  }157 158 159  private void doWork (SocketChannel channel)throws Exception160  {161   buffer.clear();162   buffer.put ("Hello,I am working,please input some thing,and i will echo to you![echo] $".getBytes());163   buffer.flip();164   channel.write (buffer);165  }166 167 }

    使用:運行此程式,然後在控制台輸入命令telnet localhost 23。

    【程式輸出結果】12-1所示。

圖12-1 輸出結果

    【程式註解】
    關於程式的解釋已經包含在程式裡面了,在這裡我們總結以下使用ServerSocket Channel開發服務端程式的過程:
    (1)分配一個ServerSocketChannel。
    (2)從ServerSocketChannel裡獲得一個對應的ServerSocket。
    (3)產生一個Selector執行個體。
    (4)把ServerSocket綁定到連接埠上。
    (5)設定ServerSocketChannel為非block模式(可選)。
    (6)在Selector裡註冊ServerSocetChannel。
    (7)用一個無限迴圈語句始終查看Selector裡是否有IO準備就緒的channel。如果有,就執行對應的處理,如果沒有,繼續迴圈。

     小 結

    在本章我們主要介紹了Java中的網路編程。Java一開始就是一種網路程式設計語言,到後來才應用到各個方面,所以在Java中進行網路編程遠比在C/C++中方便。

    我們介紹了幾個在網路編程中很重要的類,如InetAddress、URL、URLConnection、Socket、 ServerSocket、DatagramSocket、DatagramPacket、MulticastSocket等。這些類包含了進行基本網路編程的所有內容。要熟練地應用這些類,關鍵還是要多多練習。

    基於通訊端的編程基本上是客戶/伺服器模式,我們具體介紹了編寫這種模式的步驟。在執行個體方面,我們給出了一個基於TCP的通訊端客戶/伺服器程式,與此相對應,還給出了基於UDP的客戶/伺服器程式。兩者的模式是很相似的,其實這也就是編寫客戶/伺服器程式的一般模式。 (T111)

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.