客户端
import java.net.*;
import java.nio.channels.*;
import java.nio.*;
import java.io.*;
import java.nio.charset.*;
import java.util.*;
public class DatagramChannelClient
{
//DatagramChannel针对面向数据报的可选择通道
private DatagramChannel datagramChannel=null;
//ByteBuffer字节缓冲区 ByteBuffer.allocate(int capacity)设置字节缓冲区的容量
//初始化两个字节缓冲区 sendBuffer和receiveBuffer 用来接受和发送数据
private ByteBuffer sendBuffer=ByteBuffer.allocate(1024);
private ByteBuffer receiveBuffer=ByteBuffer.allocate(1024);
//Charset类
private Charset charset=Charset.forName("GBK");
//Selector SelectableChannel对象的多路复用器
private Selector selector;
public DatagramChannelClient()throws IOException
{
this(7000);
}
public DatagramChannelClient(int port)throws IOException
{
//DatagramChannel类的静态方法open()打开数据报通道
datagramChannel=DatagramChannel.open();
//InetAddress.getLocalhost()返回本地主机的IP地址
InetAddress add=InetAddress.getLocalHost();
//构造方法InetSocketAddress(InetAddress addr,int
port)根据指定的IP地址和端口号来创建套接字地址
InetSocketAddress address=new InetSocketAddress(add,port);
//设置为非阻塞模式 DatagramChannel类的configureBlocking(blooean
block)block为true则通道处于阻塞模式,block为false则通道处于非阻塞模式
datagramChannel.configureBlocking(false);
datagramChannel.socket().bind(address);
//与远程地址相连
address=new InetSocketAddress(add,8000);
//Selector类的静态方法open()打开一个选择器
selector=Selector.open();
}
public static void main(String[] args) throws IOException
{
// TODO Auto-generated method stub
int port=8793;
if(args.length>0)
{
//在参数中指定端口号
port=Integer.parseInt(args[0]);
}
final DatagramChannelClient client=new
DatagramChannelClient(port);
//receiver线程
Thread receiver=new Thread()
{
//run()方法
public void run()
{
client.receiveFromUser();
}
};
//调用start()方法 线程开始运行
receiver.start();
client.talk();
}
public void receiveFromUser()
{
try
{
//读取用户键盘输入
BufferedReader localReader=new BufferedReader(new
InputStreamReader(System.in));
String msg=null;
//按行读取数据
while((msg=localReader.readLine())!=null)
{
//synchronized关键字
synchronized(sendBuffer)
{
sendBuffer.put(encode(msg+"\r\n"));
}
if(msg.equals("bye"))
{
break;
}
}
}
catch(IOException e)
{
e.printStackTrace();
}
}
public void talk()throws IOException
{
datagramChannel.register(selector, SelectionKey.OP_READ,
SelectionKey.OP_WRITE);
while(selector.select()>0)
{
Set readyKeys=selector.selectedKeys();
Iterator it=readyKeys.iterator();
while(it.hasNext())
{
SelectionKey key=null;
try
{
key=(SelectionKey)it.next();
it.remove();
if(key.isReadable())
{
receive(key);
}
if(key.isWritable())
{
send(key);
}
}
catch(IOException e)
{
e.printStackTrace();
try
{
if(key!=null)
{
key.cancel();
key.channel().close();
}
}
catch(IOException o)
{
o.printStackTrace();
}
}
}
}
}
public void send(SelectionKey key)throws IOException
{
DatagramChannel
datagramChannel=(DatagramChannel)key.channel();
synchronized(sendBuffer)
{
sendBuffer.flip();
datagramChannel.write(sendBuffer);
sendBuffer.compact();
}
}
public void receive(SelectionKey key)throws IOException
{
DatagramChannel
datagramChannel=(DatagramChannel)key.channel();
datagramChannel.read(receiveBuffer);
receiveBuffer.flip();
String receiveData=decode(receiveBuffer);
if(receiveData.indexOf("\n")==-1)
{
return;
}
String
outputData=receiveData.substring(0,receiveData.indexOf("\n")+1);
System.out.println(outputData);
if(outputData.equals("echo:bye\r\n"))
{
key.cancel();
datagramChannel.close();
System.out.println("关闭与服务器的连接");
selector.close();
System.exit(0);
}
ByteBuffer temp=encode(outputData);
receiveBuffer.compact();
}
//解码
public String decode(ByteBuffer buffer)
{
CharBuffer charBuffer=charset.decode(buffer);
return charBuffer.toString();
}
//编码
public ByteBuffer encode(String str)
{
return charset.encode(str);
}
}
服务器端
import java.io.*;
import java.net.*;
import java.nio.*;
import java.nio.channels.*;
import java.nio.charset.*;
public class DatagramChannelServer
{
private int port=8000;
//DatagramChannel 针对面向数据报套接字的可选择通道
private DatagramChannel channel;
private final int MAX_SIZE=1024;
public DatagramChannelServer()throws IOException
{
//调用DatagramChannel类的静态方法DatagramChannel.open()打开数据报通道
channel=DatagramChannel.open();
//socket()检索与此数据报通道关联的数据报套接字
DatagramSocket socket=channel.socket();
//Socketaddress
SocketAddress localAddr=new InetSocketAddress(8000);
//DatagramSocket类的方法bind(SocketAddress addr)
将DatagramSocket绑定到指定的地址和端口
socket.bind(localAddr);
//服务器启动
System.out.println("服务器启动");
}
public String echo(String msg)
{
return "echo:"+msg;
}
public void service()
{
//ByteBuffer字节缓冲区 ByteBuffer.allocate(int capacity)分配一个新的缓冲区
capacity为缓冲区的容量
ByteBuffer receiveBuffer=ByteBuffer.allocate(MAX_SIZE);
while(true)
{
try
{
//清除字节缓冲区 将位置设置为0
receiveBuffer.clear();
InetSocketAddress
client=(InetSocketAddress)channel.receive(receiveBuffer);
//flip()反转缓冲区 首先对当前位置限制 然后将当前位置设置为零
receiveBuffer.flip();
//java.nio.charset.Charset Charset名称必须以字母或数字开头 空字符串不是合法的Charset名称
Charset名称是大小写不敏感的
//forName(String charsetName)返回命名Charset的Charset对象
decoade(ByteBuffer bb)将Charset中的字节解码成unicode字符
String
msg=Charset.forName("GBK").decode(receiveBuffer).toString();
System.out.println(client.getAddress()+":"+client.getPort()+">"+msg);
//DatagramChannel类的send(ByteBuffer src,SocketAddress
target)通过通道发送数据报
channel.send(ByteBuffer.wrap(echo(msg).getBytes()), client);
}
catch(IOException e)
{
e.printStackTrace();
}
}
}
public static void main(String[] args) throws IOException
{
// TODO Auto-generated method stub
new DatagramChannelServer().service();
}
}