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 徐辛波 阅读(9325) 评论(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  回复  更多评论   


只有注册用户登录后才能发表评论。


网站导航:
 

导航

<2009年3月>
22232425262728
1234567
891011121314
15161718192021
22232425262728
2930311234

统计

常用链接

留言簿(1)

随笔分类

随笔档案

最新随笔

最新评论

阅读排行榜

评论排行榜