您的位置:首页 > 编程语言 > Java开发

Java NIO(4) Selector 选择器,Pipe 通道

2018-02-06 17:36 543 查看

Java NIO

1. Java NIO 基本组件介绍

2. Java NIO 核心组件:Buffer 缓冲器

3. Java NIO 核心组件:Channel 通道

4. Java NIO 核心组件:Selector 选择器,Pipe 管道

Selector 选择器

Java NIO 的 Selector 选择器用于监视操控通道的行为,可用作可以进入非阻塞模式的特殊类型的通道,它可以检查一个或多个NIO通道,并确定哪个通道准备好可以进行通信,可以进行写入、读取等;



Selector 常用的 API

static Selectoropen()创建一个选择器;
voidclose()关闭选择器;
intselect([long time])返回一组 key,其相应的通道已经为 I/O 操作准备就绪;
intselectNow()同上,不过立即执行,不等待;
Set<SelectionKey>selectedKeys()返回该选择器已经选择的 key set;
一个基本的使用如下:

 

Selector selector = Selector.open();   //创建选择器


selector.select();    //选择当下的一组 key


Set<SelectionKey> selectedKeys = selector.selectedKeys();  //或者这些 key 的set


Iterator<SelectionKey> iter = selectedKeys.iterator();     //获取迭代器并进行迭代操作


while(iter.hasNext()){


   SelectionKey key = keyIterator.next();  


   if(key.isConnectable()) {  


       // The connection was established with a remote server.  


   } else if (key.isAcceptable()) {  


       // The connection was accepted by a ServerSocketChannel.  


   } else if (key.isWritable()) {  


       //  The channel is ready for writing  


   } else if (key.isReadable()) {  


       // The channel is ready for reading  


   }  


   keyIterator.remove();  


}


实际示例
以下以 Selector 在 ServerSocketChannel,SocketChannel 中的使用,示例 Selector 的实际使用场景:
服务端 TCPServer

 

public class TcpServer {


   public static void main(String[] args) throws IOException {




       ServerSocketChannel ssc  = ServerSocketChannel.open();


       ssc.configureBlocking(false);


       ssc.bind(new InetSocketAddress("127.0.0.1",2333));




       Selector selector = Selector.open();   //创建选择器


       ssc.register(selector, ssc.validOps());  // 向ServerSocketChannel 注册 Selector




       while(true){


          System.out.println("the number of selected keys are: " + selector.select());   //获取已经准备好的Channel数量


          Set keys = selector.selectedKeys();


          Iterator<SelectionKey> iter = keys.iterator();  // 获取 selectedKeys 遍历器




          while(iter.hasNext()){


              SelectionKey key = iter.next();


              


              if(key.isAcceptable()){   //当客户端通道可接收时


                 SocketChannel client = ssc.accept();  //获取客户端 SocketChannel


                 client.configureBlocking(false);    //设置为非阻塞


                 client.register(selector, SelectionKey.OP_READ);  //标记客户端通道可读


                 System.out.println("new connection from client: "+ client);


                 


            }else if(key.isReadable()){   //当客户端通道可读时


                 SocketChannel client = (SocketChannel) key.channel();  //获取客户端通道


                ByteBuffer buffer = ByteBuffer.allocate(1024);


                 client.read(buffer);


                buffer.flip();


                 System.out.println("message from client: " + Charset.forName("UTF-8").decode(buffer).toString() );


                 client.register(selector,SelectionKey.OP_WRITE);   //标记客户端为可写




            }else if(key.isWritable()){   //当客户端可写时


                 SocketChannel client = (SocketChannel) key.channel();  //获取客户端通道


                 ByteBuffer buffer = ByteBuffer.wrap("Hi, My friend!".getBytes("UTF-8"));


                 client.write(buffer);


            }


              iter.remove();


         }


      }


   }


}




客户端 TCPClient

 

public class TCPClient {


   public static void main(String[] args) throws IOException {


       


       //创建 SocketChannel,并链接 TCP 端口


       SocketChannel sc = SocketChannel.open();


       sc.connect(new InetSocketAddress("127.0.0.1", 2333));


       ByteBuffer buffer = ByteBuffer.allocate(1024);




       //向 SocketChannel 写入缓冲区数据


       buffer.put("Hello world!".getBytes("UTF-8")).flip();


       sc.write(buffer);




       //从 SocketChannel 读取数据到缓冲区


       buffer.clear();


       sc.read(buffer);


       buffer.flip();


       System.out.println("from server[" + sc.getRemoteAddress() + "] : "


              + Charset.forName("UTF-8").decode(buffer).toString());




       sc.close();


   }


}


Pipe 管道

Java NIO Pipe 管道用于在两个线程之间建立单向数据连接,一个 Pipe 包含一个 SinkChannel 接收通道和一个 SourceChannel 源通道,数据从 SinkChannel 写入,从 SourceChannel 读取;



Pipe 主要 API

static Pipeopen()打开一个管道
Pipe.SinkChannelsink()获取该管道的接收器通道;
Pipe.SourceChannelsource()获取该管道的源通道
使用示例

 

//创建管道


Pipe pipe = Pipe.open();




//向管道写入数据


Pipe.SinkChannel sinkChannel = pipe.sink();  //打开 pipe 的接收管道


ByteBuffer buffer = ByteBuffer.wrap("Hello world!".getBytes("UTF-8"));


sinkChannel.write(buffer);               //向 pipe 的接收管道写入缓冲区数据




//从管道读取数据


Pipe.SourceChannel sourceChannel = pipe.source();    //打开 pipe 的源管道


buffer = ByteBuffer.allocate(1024);


sourceChannel.read(buffer);          //从 pipe 的源管道读取数据到缓冲区


buffer.flip();


System.out.println(Charset.forName("UTF-8").decode(buffer).toString());
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: