非阻塞IO典型例子

来源:互联网 发布:淘宝红包客户端 编辑:程序博客网 时间:2024/05/01 00:48

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

import java.nio.channels.SocketChannel;

import java.util.Iterator;

import java.util.Set;

 

public class Server {

             
// 服务器端口

    
public static int port = 9994;

 

    
public Server() {

       init();

    }


 

    
public void init() {

       Selector selector 
= null;

       
try {

           
//  获得Selector实例

           selector 
= Selector.open();

           
//  获得ServerSocketChannel实例

           ServerSocketChannel serverChannel 
= ServerSocketChannel.open();

           InetSocketAddress add 
= new InetSocketAddress("localhost", port);

           
//  设为非阻塞模式,默认为阻塞模式

           serverChannel.configureBlocking(
false);

           
//  channel与一个InetSocketAddress绑定

           serverChannel.socket().bind(add);

           
//  向selector注册

           serverChannel.register(selector, SelectionKey.OP_ACCEPT);

       }
 catch (IOException e) {

           e.printStackTrace();

           
return;

       }


       
while (true{

           
try {

                      
//  如果没有准备好的channel,就在这一直阻塞

              
//  注意刚启动时,没有客户端与服务器端连接,会阻塞

              selector.select();

           }
 catch (IOException e) {

 

              e.printStackTrace();

              
break;

           }


           
//  返回已经就绪的SelctionKey,然后迭代执行

           Set readyKeys 
= selector.selectedKeys();

           
for (Iterator it = readyKeys.iterator(); it.hasNext();) {

              SelectionKey key 
= (SelectionKey) it.next();

              
//  为防止重复迭代要执行remove,在执行selector.select()时,会自动加入去掉的key

              it.remove();

              
try {

                  
//  对应于注册的OP_ACCEPT管道,在这里即ServerSocketChannel

                  
if (key.isAcceptable()) {

                     ServerSocketChannel server 
= (ServerSocketChannel) key

                            .channel();

                     
// 由于ServerSocketChannel为非阻塞模式,因此不会在这阻塞

                     SocketChannel client 
= server.accept();

                     client.configureBlocking(
false);

                     
//  表明接受到一个客户端连接,将其注册到selector

                                                                             
//  执行selector.select()时可以自动选一个channel

                     client.register(selector, SelectionKey.OP_WRITE);

                     
//  对应于注册的OP_WRITE管道,在这里即SocketChannel

                  }
 else if (key.isWritable()) {

                     SocketChannel client 
= (SocketChannel) key.channel();

                     
// 开辟20个字节的缓冲区

                     ByteBuffer buffer 
= ByteBuffer.allocate(20);

                     String str 
= "hello";

                     
//  将"hello"封装到buffer

                     buffer 
= ByteBuffer.wrap(str.getBytes());

                     
//  写入客户端

                     client.write(buffer);

                     
//  写完hello后取消通道的注册

                     key.cancel();

 

                  }


              }
 catch (IOException e) {

                  e.printStackTrace();

                  key.cancel();

                  
try {

                     
//  关闭通道

                     key.channel().close();

                  }
 catch (IOException e1) {

                     e.printStackTrace();

                  }


              }


           }
// end for

       }
// end while

 

    }


 

    
public static void main(String[] args) {

 

       Server server 
= new Server();

 

    }


 

}


客户端程序:
import java.io.IOException;

import java.net.InetSocketAddress;

import java.net.SocketAddress;

import java.nio.ByteBuffer;

import java.nio.channels.SocketChannel;

 

public class Client {

    
public Client() {

       init();

    }


 

    
public void init() {

        
try {

           SocketAddress add 
= new InetSocketAddress("localhost", Server.port);

           
// 返回SocketChannel实例,并绑定SocketAddress

           SocketChannel client 
= SocketChannel.open(add);

           client.configureBlocking(
false);

           ByteBuffer buffer 
= ByteBuffer.allocate(20);

                                        
// 从通道中读取

           client.read(buffer);

                     
// 为读取做准备

           buffer.flip();

           String result 
= "";

           
// 每次读一个字符

           
while (buffer.hasRemaining())

              result 
+= String.valueOf((char) buffer.get());

           System.out.println(result);

           client.close();

 

       }
 catch (IOException e) {

 

           e.printStackTrace();

       }


    }


 

    
public static void main(String[] args) {

       

       Client client
=null;

       
for(int i=0;i<10;i++){

          client 
= new Client();

          System.out.println(
"client "+i+" has connected");

       }
 

 

    }


 

}


 

运行结果:

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