posts - 56,  comments - 12,  trackbacks - 0

          在前面的章節里,我們討論了Java NIO的基本概念,在這一節里,我們將結合具體的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 Diion =====================
          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.Selecti;
          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, Selecti.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 // 處理每一個Selecti
          79 while (it.hasNext()) {
          80 Selecti key = (Selecti) it.next();
          81
          82 // 判斷是否有新的連接到達
          83 if (key.isAcceptable()) {
          84           //返回Selecti的ServerSocketChannel
          85 ServerSocketChannel server =
          (ServerSocketChannel) key.channel();
          86 SocketChannel channel = server.accept();
          87
          88 registerChannel (selector, channel,
          89 Selecti.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 (Selecti 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。

              【程序輸出結果】如圖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的客戶/服務器程序。兩者的模式是很相 似的,其實這也就是編寫客戶/服務器程序的一般模式。

          posted on 2007-01-18 23:55 苦笑枯 閱讀(310) 評論(0)  編輯  收藏 所屬分類: Java
          收藏來自互聯網,僅供學習。若有侵權,請與我聯系!

          <2007年1月>
          31123456
          78910111213
          14151617181920
          21222324252627
          28293031123
          45678910

          常用鏈接

          留言簿(2)

          隨筆分類(56)

          隨筆檔案(56)

          搜索

          •  

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 九江市| 庆云县| 内丘县| 新宾| 花莲市| 龙口市| 七台河市| 天全县| 英吉沙县| 富阳市| 安仁县| 武山县| 富锦市| 长泰县| 蛟河市| 手游| 淮安市| 巩义市| 古田县| 长子县| 临漳县| 于田县| 宕昌县| 新田县| 鄂尔多斯市| 霍林郭勒市| 丰原市| 宝鸡市| 绍兴县| 五峰| 张家港市| 靖江市| 巴青县| 丰都县| 东平县| 武功县| 同心县| 永济市| 化德县| 新田县| 民权县|