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 () ; 
             } 
         } 

     } 
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值