非阻塞IO典型例子

本文介绍Java非阻塞IO的应用,通过一个典型示例展示如何利用非阻塞IO提高服务器性能。示例中,服务器端使用少量线程处理大量客户端连接请求,并发送消息。

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值