Java NIO学习-UDP的例子

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 徐辛波([email protected]) 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  徐辛波([email protected])
  * 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 () ;
             }
         }

     }
}

你可能感兴趣的:(Java NIO学习-UDP的例子)