文档章节

Netty进阶基础篇之NIO 非阻塞通信(6)

木九天
 木九天
发布于 07/14 14:51
字数 1107
阅读 15
收藏 0

1、图览

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

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();
      }
   }
}

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();
   }
}

© 著作权归作者所有

木九天

木九天

粉丝 217
博文 255
码字总数 194330
作品 0
海淀
程序员
私信 提问
Java分布式框架netty之NIO框架区别分析

Netty概述: 1、netty是基于Java NIO的网络应用框架,client-server框架 2、Netty是一个高性能、异步事件驱动的NIO框架,它提供了对TCP、UDP和文件传输的支持, 作为一个异步NIO框架,Netty...

架构师springboot
2018/11/12
485
0
Qzone 微信 Java高级——dubbo源码分析之远程通信 netty

Java高级——dubbo源码分析之远程通信 netty dubbo 底层通信选择了 netty 这个 nio 框架做为默认的网络通信框架并且通过自定义协议进行通信。dubbo 支持以下网络通信框架: Netty(默认) Min...

Java架构师那些事
2018/08/29
0
0
Netty高性能架构的理解之道

Netty的简单介绍 Netty 是一个 NIO client-server(客户端服务器)框架,使用 Netty 可以快速开发网络应用,例如服务器和客户 端协议。 Netty 提供了一种新的方式来使开发网络应用程序,这种新...

烂猪皮
2018/05/04
118
2
少啰嗦!一分钟带你读懂Java的NIO和经典IO的区别

本文引用了“架构师社区”公众号的《史上讲的最好的Java NIO与IO的区别与应用》一文部分内容,感谢原作者的技术分享。 1、引言 很多初涉网络编程的程序员,在研究Java NIO(即异步IO)和经典...

JackJiang2011
06/25
0
0
Netty高性能之道

背景 1.1. 惊人的性能数据 最近一个圈内朋友通过私信告诉我,通过使用Netty4 + Thrift压缩二进制编解码技术,他们实现了10W TPS(1K的复杂POJO对象)的跨节点远程服务调用。相比于传统基于J...

HenrySun
2016/04/19
232
0

没有更多内容

加载失败,请刷新页面

加载更多

Java注解合并,注解继承

spring中有时候一个类上面标记很多注解。 实际上Java注解可以进行继承(也就是把多个注解合并成1个) 比如说SpringMVC的注解 @RestController@RequestMapping("/person") 可以合并为一个 @P...

物种起源-达尔文
21分钟前
4
0
撤消Git中一个文件的工作副本修改?

在最后一次提交之后,我修改了工作副本中的一堆文件,但是我想撤消对这些文件之一的更改,例如将其重置为与最新提交相同的状态。 但是,我只想撤消仅一个文件的工作副本更改,而没有其他操作...

技术盛宴
57分钟前
4
0
Qt编写气体安全管理系统28-模拟工具

一、前言 模拟工具在一些涉及到硬件通信的程序中特别有用,也特别需要,回顾这十年来做过的项目,95%的项目都是软硬件交互的,貌似软硬件结合的项目更有生命力一些,纯软件的或者纯硬件的,并...

飞扬青云
今天
4
0
关于生活方式

生活就是生活,但难免和工作混在一起,所以要建立自己的生活方式,把工作稍微隔开点。 首先呢,每周放假的两天肯定会: 洗衣服,收拾屋子,列计划是必须要做的事情。 (这里可能还包含一些处...

T型人才追梦者
今天
6
0
JVM

一、JVM一些基本概念 1、JVM和普通虚拟机 JVM:Java Virtual Machine,程序自己独立的运行环境;堆栈、寄存器、字节码指令;可以运行多种语言:Java、Scala、Grovvy; 普通虚拟机:能完整提供...

请把小熊还给我_m
今天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部