Java NIO學習-UDP的例子

          這幾天需要實現一個底層基于UDP的協議,該協議底層使用UDP傳輸但是具有擁塞控制、超時重發、數據確認等功能又比TCP簡單 (RUDP,Reliable UDP)。在實現協議底層的UDP服務時準備使用Java的NIO,在網上查資料都是以TCP為例講的,于是自己研究了一下基于UDP的NIO。

          NIO的思路是基于多路選擇的,即由原來的每個連接都由一個線程來等待消息,改為每個連接都在選擇器上注冊,由選擇器來等待。當然NIO引入了很多新的概念,如Channel,Buffer、Charset、Selector等,使得編程更簡潔、更面向對象化。

          下面貼出用NIO API改造成UDP示例代碼,注意其中使用Charset來編碼解碼的過程(當然Charset還支持很多其他編碼不僅局限于默認編碼)以及Buffer的使用。

          package sinpo.usagedemo;

          import java.net.DatagramSocket;
          import java.net.InetSocketAddress;
          import java.net.SocketAddress;
          import java.nio.ByteBuffer;
          import java.nio.CharBuffer;
          import java.nio.channels.DatagramChannel;
          import java.nio.channels.SelectionKey;
          import java.nio.channels.Selector;
          import java.nio.charset.Charset;
          import java.util.Iterator;
          import java.util.Set;

          /**
          * @author 徐辛波(sinpo.xu@hotmail.com) Oct 19, 2008
          */
          public class UDPServer extends Thread {
          public void run () {
          Selector selector = null ;
          try {
          DatagramChannel channel = DatagramChannel.open () ;
          DatagramSocket socket = channel.socket () ;
          channel.configureBlocking ( false ) ;
          socket.bind ( new InetSocketAddress ( 5057 )) ;

          selector = Selector.open () ;
          channel.register ( selector, SelectionKey.OP_READ ) ;
          } catch ( Exception e ) {
          e.printStackTrace () ;
          }

          ByteBuffer byteBuffer = ByteBuffer.allocate ( 65536 ) ;
          while ( true ) {
          try {
          int eventsCount = selector.select () ;
          if ( eventsCount > 0 ) {
          Set selectedKeys = selector.selectedKeys () ;
          Iterator iterator = selectedKeys.iterator () ;
          while ( iterator.hasNext ()) {
          SelectionKey sk = ( SelectionKey ) iterator.next () ;
          iterator.remove () ;
          if ( sk.isReadable ()) {
          DatagramChannel datagramChannel = ( DatagramChannel ) sk
          .channel () ;
          SocketAddress sa = datagramChannel
          .receive ( byteBuffer ) ;
          byteBuffer.flip () ;

          // 測試:通過將收到的ByteBuffer首先通過缺省的編碼解碼成CharBuffer 再輸出
          CharBuffer charBuffer = Charset.defaultCharset ()
          .decode ( byteBuffer ) ;
          System.out.println ( "receive message:"
          + charBuffer.toString ()) ;
          byteBuffer.clear () ;

          String echo = "This is the reply message from 服務器。" ;
          ByteBuffer buffer = Charset.defaultCharset ()
          .encode ( echo ) ;
          datagramChannel.write ( buffer ) ;
          }
          }
          }
          } catch ( Exception e ) {
          e.printStackTrace () ;
          }
          }

          }

          public static void main ( String [] args ) {
          new UDPServer () .start () ;
          }
          }
          Client
          package  sinpo.usagedemo;

          import  java.net.InetSocketAddress;
          import  java.net.SocketAddress;
          import  java.nio.ByteBuffer;
          import  java.nio.channels.DatagramChannel;
          import  java.nio.channels.SelectionKey;
          import  java.nio.channels.Selector;
          import  java.nio.charset.Charset;
          import  java.util.Iterator;
          import  java.util.Set;

          /**
            @author  徐辛波(sinpo.xu@hotmail.com)
            * Oct 19, 2008
            */
          public class  UDPClient  extends  Thread  {
               public  void  run () {
                   DatagramChannel channel =  null ;
                   Selector selector =  null ;
                   try  {
                       channel = DatagramChannel.open () ;
                       channel.configureBlocking ( false ) ;
                       SocketAddress sa =  new  InetSocketAddress ( "localhost" 5057 ) ;
                       channel.connect ( sa ) ;
                   catch  ( Exception e ) {
                       e.printStackTrace () ;
                   }

                   try  {
                       selector = Selector.open () ;
                       channel.register ( selector, SelectionKey.OP_READ ) ;
                       channel.write ( Charset.defaultCharset () .encode ( "Tell me your time" )) ;
                   catch  ( Exception e ) {
                       e.printStackTrace () ;
                   }
                  
                   ByteBuffer byteBuffer = ByteBuffer.allocate ( 100 ) ;
                   while  ( true ) {
                       try  {
                           int  eventsCount = selector.select () ;
                           if  ( eventsCount >  0 ) {
                               Set selectedKeys = selector.selectedKeys () ;
                               Iterator iterator = selectedKeys.iterator () ;
                               while  ( iterator.hasNext ()) {
                                   SelectionKey sk =  ( SelectionKey iterator.next () ;
                                   iterator.remove () ;
                                   if  ( sk.isReadable ()) {
                                       DatagramChannel datagramChannel =  ( DatagramChannel sk
                                               .channel () ;
                                       datagramChannel.read ( byteBuffer ) ;
                                       byteBuffer.flip () ;
                                      
                                       //TODO 將報文轉化為RUDP消息并調用RUDP協議處理器來處理
                                      
                                       System.out.println ( Charset.defaultCharset () .decode (
                                               byteBuffer ) .toString ()) ;
                                       byteBuffer.clear () ;
                                       datagramChannel.write ( Charset.defaultCharset ()
                                               .encode ( "Tell me your time" )) ;
                                   }
                               }
                           }
                       catch  ( Exception e ) {
                           e.printStackTrace () ;
                       }
                   }

               }
          }

          posted on 2008-10-20 22:38 徐辛波 閱讀(9339) 評論(11)  編輯  收藏 所屬分類: source pieces

          評論

          # re: Java NIO學習-UDP的例子 2008-10-22 20:47 楊愛友

          學習!  回復  更多評論   

          # re: Java NIO學習-UDP的例子 2008-10-23 17:41 yyk

          能不能把Client的代碼貼出來 謝謝  回復  更多評論   

          # re: Java NIO學習-UDP的例子 2008-10-23 20:10 徐辛波

          貼出來了 第一次可能是由于HTML原因沒有顯示出來。  回復  更多評論   

          # re: Java NIO學習-UDP的例子 2008-10-24 09:03 yyk

          非常感謝,小弟正在學習這方面的東西。再次感謝了!  回復  更多評論   

          # re: Java NIO學習-UDP的例子 2008-11-20 15:14 Mr.Right

          NIO用在UDP上沒必要吧
          他不是面向鏈接的 針對DatagramPacket就可以處理,然后再弄個DatagramSocket發送出去就OK了
          照你的寫法感覺--沒意義 沒有解決實際的問題
          NIO 用在TCP上面還能夠減少線程 用在UDP上面就免了吧  回復  更多評論   

          # re: Java NIO學習-UDP的例子 2008-11-20 18:39 徐辛波

          @Mr.Right
          1、nio對讀寫提供了一致的抽象-都是面向channel進行操作,使得對udp和tcp的操作更優雅。
          2、udp監聽程序如果不用nio的selector機制則仍需要不間斷的輪詢是否有數據到達;
          3、nio提供了ByteBuffer和CharSet等更易用的輔助類,udp程序轉到nio后能更方便的使用這些。  回復  更多評論   

          # re: Java NIO學習-UDP的例子 2008-12-25 14:18 有錯,無法回寫

          有錯,無法回寫  回復  更多評論   

          # re: Java NIO學習-UDP的例子 2009-03-10 15:36 ylq

          datagramChannel.write ( buffer ,sa) ;這樣就好了...初學者...不知道樓主是不是要這個意思....  回復  更多評論   

          # re: Java NIO學習-UDP的例子[未登錄] 2009-06-11 16:06

          datagramChannel.read ( byteBuffer ) ;
          報錯

          Java.net.PortUnreachableException  回復  更多評論   

          # re: Java NIO學習-ddddd[未登錄] 2010-05-21 10:21 ddd

          ddd  回復  更多評論   

          # re: Java NIO學習-UDP的例子 2015-07-01 09:19 kwb

          @ylq
          應該是send  回復  更多評論   

          導航

          <2015年7月>
          2829301234
          567891011
          12131415161718
          19202122232425
          2627282930311
          2345678

          統計

          常用鏈接

          留言簿(1)

          隨筆分類

          隨筆檔案

          最新隨筆

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 于田县| 吴桥县| 万盛区| 古浪县| 虹口区| 台前县| 道孚县| 会宁县| 南宁市| 吉木乃县| 许昌市| 吴江市| 宜章县| 丰镇市| 滨州市| 抚宁县| 九江县| 无棣县| 老河口市| 常宁市| 邛崃市| 山阳县| 商洛市| 祥云县| 云南省| 利津县| 宁城县| 昌吉市| 宜君县| 桐乡市| 玉田县| 陆河县| 凤凰县| 白城市| 宝鸡市| 瑞昌市| 宁陕县| 泰顺县| 浦县| 定西市| 普兰店市|