一个典型的非阻塞IO程序

   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

 
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值