Netty中NIO非阻塞通信案例分析

本篇内容主要讲解“Netty中NIO非阻塞通信案例分析”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Netty中NIO非阻塞通信案例分析”吧!

1、图览

由下图可以看出,NIO非阻塞几个属性之间的关系:多个不同客户(Socket)进入餐厅(系统)之前,先经过餐厅大门(ServerSocketChannel),这个时候门口有指导服务员(SelectionKey),看到客户(Socket)进来后,会为你安排就座(register注册到监听器中),然后点餐服务员接受到客户(Socket)被注册的关系,根据你是刚刚安排就座的客户为你上菜单,进行上菜操作。

Netty中NIO非阻塞通信案例分析

1.2 SelectionKey

表示 SelectableChannel 和 Selector 之间的注册关系。每次向 选择器注册通道时就会选择一个事件(选择键)。选择键包含两个表示为整 数值的操作集。操作集的每一位都表示该键的通道所支持的一类可选择操作。

1.3 register

当调用 register(Selector sel, int ops) 将通道注册选择器时,选择器对通道的监听事件,需要通过第二个参数 ops 指定。

1.4 监听类型

可以监听的事件类型(可使用 SelectionKey 的四个常量表示):

读 : SelectionKey.OP_READ (1)

写 : SelectionKey.OP_WRITE (4)

连接:SelectionKey.OP_CONNECT (8)

接收 : SelectionKey.OP_ACCEPT (16)

若注册时不止监听一个事件,则可以使用“位或”操作符连接

//注册监听事件
int intersetSet = SelectionKey.OP_READ | SelectionKey.OP_WRITE;

SelectionKey的使用

方法

描述

int interestOps()

获取感兴趣事件集合

int readyOps()

获取通道已经准备就绪的操作的集合

SelectableChannel  channel()

获取注册通道

Selector  selector()

返回选择器

boolean isReadable()

检测 Channal 中读事件是否就绪

boolean isWritable()

检测 Channal 中写事件是否就绪

boolean isConnectable()

检测 Channel 中连接是否就绪

boolean isAcceptable()

检测 Channel 中接收是否就绪

Selector方法

方法

描述

Set<SelectionKey> keys()

所有的 SelectionKey 集合。代表注册在该Selector上的Channel

selectedKeys()

被选择的 SelectionKey 集合。返回此Selector的已选择键集

int select()

监控所有注册的Channel,当它们中间有需要处理的 IO 操作时, 该方法返回,并将对应得的 SelectionKey 加入被选择的 SelectionKey 集合中,该方法返回这些 Channel 的数量。

int select(long timeout)

可以设置超时时长的 select() 操作

int selectNow()

执行一个立即返回的 select() 操作,该方法不会阻塞线程

Selector wakeup()

使一个还未返回的 select() 方法立即返回

void close()

关闭该选择器

2、Tcp网络非阻塞通信
//客户端
@Test
public void client() throws IOException{
   //1. 获取通道
   SocketChannel sChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 8085));
   
   //2. 切换非阻塞模式
   sChannel.configureBlocking(false);
   
   //3. 分配指定大小的缓冲区
   ByteBuffer buf = ByteBuffer.allocate(1024);
   
   //4. 发送数据给服务端
   String str = "mujiutian";
   
   while(!StringUtils.isEmpty(str)){
      buf.put((new Date().toString() + "\n" + str).getBytes());
      buf.flip();
      sChannel.write(buf);
      buf.clear();
      str = "";
   }
   
   //5. 关闭通道
   sChannel.close();
}

//服务端
@Test
public void server() throws IOException{
   //1. 获取通道
   ServerSocketChannel ssChannel = ServerSocketChannel.open();
   
   //2. 切换非阻塞模式
   ssChannel.configureBlocking(false);
   
   //3. 绑定连接
   ssChannel.bind(new InetSocketAddress(8085));
   
   //4. 获取选择器
   Selector selector = Selector.open();
   
   //5. 将通道注册到选择器上, 并且指定“监听接收事件”
   ssChannel.register(selector, SelectionKey.OP_ACCEPT);
   
   //6. 轮询式的获取选择器上已经“准备就绪”的事件
   while(selector.select() > 0){
      
      //7. 获取当前选择器中所有注册的“选择键(已就绪的监听事件)”
      Iterator<SelectionKey> it = selector.selectedKeys().iterator();
      
      while(it.hasNext()){
         //8. 获取准备“就绪”的是事件
         SelectionKey sk = it.next();
         
         //9. 判断具体是什么事件准备就绪
         if(sk.isAcceptable()){
            //10. 若“接收就绪”,获取客户端连接
            SocketChannel sChannel = ssChannel.accept();
            
            //11. 切换非阻塞模式
            sChannel.configureBlocking(false);
            
            //12. 将该通道注册到选择器上
            sChannel.register(selector, SelectionKey.OP_READ);
         }else if(sk.isReadable()){
            //13. 获取当前选择器上“读就绪”状态的通道
            SocketChannel sChannel = (SocketChannel) sk.channel();
            
            //14. 读取数据
            ByteBuffer buf = ByteBuffer.allocate(1024);
            
            int len = 0;
            while((len = sChannel.read(buf)) > 0 ){
               buf.flip();
               System.out.println(new String(buf.array(), 0, len));
               buf.clear();
            }
         }
         
         //15. 取消选择键 SelectionKey
         it.remove();
      }
   }
}

Netty中NIO非阻塞通信案例分析

3、Udp网络非阻塞通信
@Test
public void send() throws IOException{
   DatagramChannel dc = DatagramChannel.open();
   
   dc.configureBlocking(false);
   
   ByteBuffer buf = ByteBuffer.allocate(1024);
   
   Scanner scan = new Scanner(System.in);
   
   while(scan.hasNext()){
      String str = scan.next();
      buf.put((new Date().toString() + ":\n" + str).getBytes());
      buf.flip();
      dc.send(buf, new InetSocketAddress("127.0.0.1", 9898));
      buf.clear();
   }
   
   dc.close();
}

@Test
public void receive() throws IOException{
   DatagramChannel dc = DatagramChannel.open();
   
   dc.configureBlocking(false);
   
   dc.bind(new InetSocketAddress(9898));
   
   Selector selector = Selector.open();
   
   dc.register(selector, SelectionKey.OP_READ);
   
   while(selector.select() > 0){
      Iterator<SelectionKey> it = selector.selectedKeys().iterator();
      
      while(it.hasNext()){
         SelectionKey sk = it.next();
         
         if(sk.isReadable()){
            ByteBuffer buf = ByteBuffer.allocate(1024);
            
            dc.receive(buf);
            buf.flip();
            System.out.println(new String(buf.array(), 0, buf.limit()));
            buf.clear();
         }
      }
      
      it.remove();
   }
}

到此,相信大家对“Netty中NIO非阻塞通信案例分析”有了更深的了解,不妨来实际操作一番吧!这里是亿速云网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!