Java NIO Demo 在读Amoeba源码的时候,里面采用java NIO进行通信管理,以前也了解过一些关于这方面的知识但是都不太系统,最近两天抽时间对这块进行一下扫盲。我主要参考以下两篇文章,个人认为这两篇文章还是不错的入门级文章,讲的比较通俗易懂。
1.http://www.ibm.com/developerworks/cn/education/java/j-nio/section11.html
比较系统的讲述了Channel(通道)、Buffer(缓冲区)、position,limit,capacity in buffer等;其示例代码在:
http://code.google.com/p/astudy/source/browse/trunk/applications/astudy/nio/MultiPortEcho.java?spec=svn141&r=141下
2.http://tutorials.jenkov.com/java-nio/index.html
这个站点也是一个不错的入门级别介绍,虽然是e文,但讲解的比较细致。
3.我的demo
这个小例子,模拟了一个echo服务,客户端向echo服务器发送一段信息,echo收到信息后,返回给客户端,然后,连接关闭。代码如下:
<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->
/***************************************/
客户端代码:
package com.zxl.channel;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.Set;
public class EchoClient {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
SocketChannel channel = SocketChannel.open();
channel.configureBlocking(false);
InetSocketAddress s = new InetSocketAddress("localhost",2000);
channel.connect(s);
Selector selector = Selector.open();
channel.register(selector, SelectionKey.OP_CONNECT|SelectionKey.OP_READ);
Charset charset=Charset.forName("GBK");
boolean isFinished = false;
while(!isFinished){
int num = selector.select();
if(num>0){
Set<SelectionKey> keys = selector.selectedKeys();
for(SelectionKey k:keys){
if(k.isConnectable()){
SocketChannel sc = (SocketChannel) k.channel();
sc.configureBlocking(false);
sc.finishConnect();
sc.register(selector, SelectionKey.OP_READ);
ByteBuffer echoBuffer = ByteBuffer.allocate(1024);
ByteBuffer info =charset.encode("好了克隆技术杜洛克防水堵漏开发!");
echoBuffer.put(info);
echoBuffer.flip();
sc.write(echoBuffer);
echoBuffer.clear();
}else if (k.isValid() && k.isReadable()) {
ByteBuffer echoBuffer = ByteBuffer.allocate(1024);
SocketChannel sc = (SocketChannel) k.channel();
sc.read(echoBuffer);
echoBuffer.flip();
System.out.println("echo server return:"+charset.decode(echoBuffer).toString());
echoBuffer.clear();
isFinished = true;
k.cancel();
sc.close();
selector.close();
}
}
}
}
}
}
/*********************************************/
服务端代码:
package com.zxl.channel;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.Set;
public class MultiPortEchoServer {
private Charset charset=Charset.forName("GBK");
private int[] ports;
/**
* @param args
*/
public static void main(String[] args) {
int[] ps = {2000,2001}; //默认监听2000,2001端口
new MultiPortEchoServer(ps);
}
public MultiPortEchoServer(int[] ports){
this.ports = ports;
try {
go();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void go() throws IOException{
Selector selector = Selector.open();
for(int i=0;i<ports.length;i++){
ServerSocketChannel channel = ServerSocketChannel.open();
channel.configureBlocking(false);
ServerSocket socket = channel.socket();
InetSocketAddress address = new InetSocketAddress("localhost",ports[i]);
socket.bind(address);
//注册接受连接事件
channel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println( "Going to listen on "+ports[i] );
}
while(true){
int num = selector.select();
Set<SelectionKey> keys = selector.selectedKeys();
Iterator<SelectionKey> iter = keys.iterator();
while(iter.hasNext()){
SelectionKey key = iter.next();
if((key.readyOps()&SelectionKey.OP_ACCEPT)==SelectionKey.OP_ACCEPT){
ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
SocketChannel sc = ssc.accept();
sc.configureBlocking(false);
sc.register(selector, SelectionKey.OP_READ);
iter.remove();
}else if((key.readyOps()&SelectionKey.OP_READ)==SelectionKey.OP_READ){
SocketChannel sc = (SocketChannel) key.channel();
if(!sc.isOpen()){
selector = Selector.open();
}else{
ByteBuffer echoBuffer = ByteBuffer.allocate(1024);
//int x = sc.read(echoBuffer);
while(sc.read(echoBuffer)>0){
System.out.println( "Echoed "+charset.decode(echoBuffer).toString()+" from "+sc.socket().getInetAddress().getHostAddress() );
echoBuffer.flip();
sc.write(echoBuffer);
echoBuffer.clear();
}
iter.remove();
/*返回信息后关闭连接*/
key.cancel();
sc.close();
}
}
}
keys.clear();
}
}
}
客户端代码:
package com.zxl.channel;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.Set;
public class EchoClient {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
SocketChannel channel = SocketChannel.open();
channel.configureBlocking(false);
InetSocketAddress s = new InetSocketAddress("localhost",2000);
channel.connect(s);
Selector selector = Selector.open();
channel.register(selector, SelectionKey.OP_CONNECT|SelectionKey.OP_READ);
Charset charset=Charset.forName("GBK");
boolean isFinished = false;
while(!isFinished){
int num = selector.select();
if(num>0){
Set<SelectionKey> keys = selector.selectedKeys();
for(SelectionKey k:keys){
if(k.isConnectable()){
SocketChannel sc = (SocketChannel) k.channel();
sc.configureBlocking(false);
sc.finishConnect();
sc.register(selector, SelectionKey.OP_READ);
ByteBuffer echoBuffer = ByteBuffer.allocate(1024);
ByteBuffer info =charset.encode("好了克隆技术杜洛克防水堵漏开发!");
echoBuffer.put(info);
echoBuffer.flip();
sc.write(echoBuffer);
echoBuffer.clear();
}else if (k.isValid() && k.isReadable()) {
ByteBuffer echoBuffer = ByteBuffer.allocate(1024);
SocketChannel sc = (SocketChannel) k.channel();
sc.read(echoBuffer);
echoBuffer.flip();
System.out.println("echo server return:"+charset.decode(echoBuffer).toString());
echoBuffer.clear();
isFinished = true;
k.cancel();
sc.close();
selector.close();
}
}
}
}
}
}
/*********************************************/
服务端代码:
package com.zxl.channel;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.Set;
public class MultiPortEchoServer {
private Charset charset=Charset.forName("GBK");
private int[] ports;
/**
* @param args
*/
public static void main(String[] args) {
int[] ps = {2000,2001}; //默认监听2000,2001端口
new MultiPortEchoServer(ps);
}
public MultiPortEchoServer(int[] ports){
this.ports = ports;
try {
go();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void go() throws IOException{
Selector selector = Selector.open();
for(int i=0;i<ports.length;i++){
ServerSocketChannel channel = ServerSocketChannel.open();
channel.configureBlocking(false);
ServerSocket socket = channel.socket();
InetSocketAddress address = new InetSocketAddress("localhost",ports[i]);
socket.bind(address);
//注册接受连接事件
channel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println( "Going to listen on "+ports[i] );
}
while(true){
int num = selector.select();
Set<SelectionKey> keys = selector.selectedKeys();
Iterator<SelectionKey> iter = keys.iterator();
while(iter.hasNext()){
SelectionKey key = iter.next();
if((key.readyOps()&SelectionKey.OP_ACCEPT)==SelectionKey.OP_ACCEPT){
ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
SocketChannel sc = ssc.accept();
sc.configureBlocking(false);
sc.register(selector, SelectionKey.OP_READ);
iter.remove();
}else if((key.readyOps()&SelectionKey.OP_READ)==SelectionKey.OP_READ){
SocketChannel sc = (SocketChannel) key.channel();
if(!sc.isOpen()){
selector = Selector.open();
}else{
ByteBuffer echoBuffer = ByteBuffer.allocate(1024);
//int x = sc.read(echoBuffer);
while(sc.read(echoBuffer)>0){
System.out.println( "Echoed "+charset.decode(echoBuffer).toString()+" from "+sc.socket().getInetAddress().getHostAddress() );
echoBuffer.flip();
sc.write(echoBuffer);
echoBuffer.clear();
}
iter.remove();
/*返回信息后关闭连接*/
key.cancel();
sc.close();
}
}
}
keys.clear();
}
}
}