程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 使用Java NIO提高服務端程序的性能

使用Java NIO提高服務端程序的性能

編輯:關於JAVA

 結合具體的Java Socket編程,討論使用NIO提高服務端程序的性能的問題。

  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.Java

  3 // 程序目的:學習Java NIO#SocketChannel

  4 // ==============================================================

  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;

  18

  19 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 Exception

  30 {

  31 SocketChannelDemo server=new SocketChannelDemo();

  32 server.init(args);

  33 server.startWork();

  34 }

  35

  36

  37 public void init (String [] argv)throws Exception

  38 {

  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 // 分配一個ServerSocketChannel

  48 serverChannel = ServerSocketChannel.open();

  49 // 從ServerSocketChannel裡獲得一個對應的Socket

  50 serverSocket = serverChannel.socket();

  51 // 生成一個Selector

  52 selector = Selector.open();

  53

  54 // 把Socket綁定到端口上

  55 serverSocket.bind (new InetSocketAddress (port));

  56 //serverChannel為非bolck

  57 serverChannel.configureBlocking (false);

  58

  59 // 通過Selector注冊ServerSocetChannel

  60 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的selectedkeys

  76 Iterator it = selector.selectedKeys().iterator();

  77

  78 // 處理每一個SelectionKey

  79 while (it.hasNext()) {

  80 SelectionKey key = (SelectionKey) it.next();

  81

  82 // 判斷是否有新的連接到達

  83 if (key.isAcceptable()) {

  84           //返回SelectionKey的ServerSocketChannel

  85 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 //刪除 selectedkeys

  102 it.remove();

  103 }

  104 }

  105 }

  106 protected void registerChannel (Selector selector,

  107 SelectableChannel channel, int ops)

  108 throws Exception

  109 {

  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 Exception

  123 {

  124

  125

  126 SocketChannel socketChannel = (SocketChannel) key.channel();

  127 int count;

  128

  129 buffer.clear(); // 清空buffer

  130

  131 // 讀取所有的數據

  132 while ((count = socketChannel.read (buffer)) > 0) {

  133 buffer.flip();

  134

  135 // send the data, don′t assume it goes all at once

  136 while (buffer.hasRemaining())

  137 {

  138 //如果收到回車鍵,則在返回的字符前增加[echo]$字樣

  139 if(buffer.get()==(char)13)

  140 {

  141 buffer.clear();

  142 buffer.put("[echo]___FCKpd___0quot;.getBytes());

  143 buffer.flip();

  144

  145 }

  146 socketChannel.write (buffer);//在Socket裡寫數據

  147 }

  148

  149 buffer.clear(); // 清空buffer

  150 }

  151

  152 if (count < 0) {

  153 // count<0,說明已經讀取完畢

  154 socketChannel.close();

  155 }

  156 }

  157

  158

  159 private void doWork (SocketChannel channel)throws Exception

  160 {

  161 buffer.clear();

  162 buffer.put ("

  Hello,I am working,please input some thing,and i will echo to you!

  [echo]

  ___FCKpd___0quot;.getBytes());

  163 buffer.flip();

  164 channel.write (buffer);

  165 }

  166

  167 }

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

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