Java 非阻塞IO常用于高性能的服务器程序。对于阻塞式IO常常需要多个线程来处理客户端的请求,由于线程的开销较大,往往使服务器性能下降很快。而非阻塞IO只需几个线程就可以胜任大量的请求。对于p2p软件(例如BT软件),也常常使用非阻塞IO,来实现文件交换。
下面是一个典型的非阻塞IO程序。客户端向服务器端发起10个连接,服务器端向每个客户端发送”Hello”,并打印出来。
服务器端程序:
importjava.io.IOException;
importjava.net.InetSocketAddress;
importjava.nio.ByteBuffer;
importjava.nio.channels.SelectionKey;
importjava.nio.channels.Selector;
importjava.nio.channels.ServerSocketChannel;
importjava.nio.channels.SocketChannel;
importjava.util.Iterator;
importjava.util.Set;


publicclassServer{
//服务器端口
publicstaticintport=9994;


publicServer(){
init();
}


publicvoidinit(){
Selectorselector=null;
try{
//获得Selector实例
selector=Selector.open();
//获得ServerSocketChannel实例
ServerSocketChannelserverChannel=ServerSocketChannel.open();
InetSocketAddressadd=newInetSocketAddress("localhost",port);
//设为非阻塞模式,默认为阻塞模式
serverChannel.configureBlocking(false);
//channel与一个InetSocketAddress绑定
serverChannel.socket().bind(add);
//向selector注册
serverChannel.register(selector,SelectionKey.OP_ACCEPT);
}catch(IOExceptione){
e.printStackTrace();
return;
}
while(true){
try{
//如果没有准备好的channel,就在这一直阻塞
//注意刚启动时,没有客户端与服务器端连接,会阻塞
selector.select();
}catch(IOExceptione){


e.printStackTrace();
break;
}
//返回已经就绪的SelctionKey,然后迭代执行
SetreadyKeys=selector.selectedKeys();
for(Iteratorit=readyKeys.iterator();it.hasNext();){
SelectionKeykey=(SelectionKey)it.next();
//为防止重复迭代要执行remove,在执行selector.select()时,会自动加入去掉的key
it.remove();
try{
//对应于注册的OP_ACCEPT管道,在这里即ServerSocketChannel
if(key.isAcceptable()){
ServerSocketChannelserver=(ServerSocketChannel)key
.channel();
//由于ServerSocketChannel为非阻塞模式,因此不会在这阻塞
SocketChannelclient=server.accept();
client.configureBlocking(false);
//表明接受到一个客户端连接,将其注册到selector
//执行selector.select()时可以自动选一个channel
client.register(selector,SelectionKey.OP_WRITE);
//对应于注册的OP_WRITE管道,在这里即SocketChannel
}elseif(key.isWritable()){
SocketChannelclient=(SocketChannel)key.channel();
//开辟20个字节的缓冲区
ByteBufferbuffer=ByteBuffer.allocate(20);
Stringstr="hello";
//将"hello"封装到buffer
buffer=ByteBuffer.wrap(str.getBytes());
//写入客户端
client.write(buffer);
//写完hello后取消通道的注册
key.cancel();


}
}catch(IOExceptione){
e.printStackTrace();
key.cancel();
try{
//关闭通道
key.channel().close();
}catch(IOExceptione1){
e.printStackTrace();
}
}
}//endfor
}//endwhile


}


publicstaticvoidmain(String[]args){


Serverserver=newServer();


}


}
客户端程序:
importjava.io.IOException;
importjava.net.InetSocketAddress;
importjava.net.SocketAddress;
importjava.nio.ByteBuffer;
importjava.nio.channels.SocketChannel;


publicclassClient{
publicClient(){
init();
}


publicvoidinit(){
try{
SocketAddressadd=newInetSocketAddress("localhost",Server.port);
//返回SocketChannel实例,并绑定SocketAddress
SocketChannelclient=SocketChannel.open(add);
client.configureBlocking(false);
ByteBufferbuffer=ByteBuffer.allocate(20);
//从通道中读取
client.read(buffer);
//为读取做准备
buffer.flip();
Stringresult="";
//每次读一个字符
while(buffer.hasRemaining())
result+=String.valueOf((char)buffer.get());
System.out.println(result);
client.close();


}catch(IOExceptione){


e.printStackTrace();
}
}


publicstaticvoidmain(String[]args){


Clientclient=null;
for(inti=0;i<10;i++){
client=newClient();
System.out.println("client"+i+"hasconnected");
}


}


}
运行结果:
hello
client 0 has connected
hello
client 1 has connected
hello
client 2 has connected
hello
client 3 has connected
hello
client 4 has connected
hello
client 5 has connected
hello
client 6 has connected
hello
client 7 has connected
hello
client 8 has connected
hello
client 9 has connected
本文介绍Java非阻塞IO的应用,通过一个典型示例展示如何利用非阻塞IO提高服务器性能。示例中,服务器端使用少量线程处理大量客户端连接请求,并发送消息。
2895

被折叠的 条评论
为什么被折叠?



