当前位置: 首页 > news >正文

Java NIO 基础

Java NIO 基础

  • 1. NIO 介绍
  • 2. NIO 三大组件
    • 2.1 Channel
      • 2.1.1 常见的 Channel
      • 2.1.2 常用方法
    • 2.2 Buffer
      • 2.2.1 常见的 Buffer
      • 2.2.2 重要属性
      • 2.2.3 常用方法
    • 2.3 Selector
      • 2.3.1 四种事件类型

1. NIO 介绍

NIO(non-blocking io):非阻塞IO,JDK1.4 引入。

2. NIO 三大组件

2.1 Channel

Channer是读写数据的双向通道,类似于传统IO中的Stream,但是Stream只能单向操作。如:InputStream只能读操作,OutputStream只能写操作。

2.1.1 常见的 Channel

  • FileChannel:文件IO通道,用于文件的读写
  • DatagramChannel:UDP协议数据报通信
  • SocketChannel:网络套接字IO通道,TCP协议客户端
  • ServerSocketChannel:网络套接字IO通道,TCP协议服务端

2.1.2 常用方法

  • read(ByteBuffer buffer):从Channel中读取到ByteBuffer中,如果Channel中没有数据会一直堵塞到可读
  • read(ByteBuffer buffer,Long timeout):从Channel中读取到ByteBuffer中,超过时间会报错
  • write(ByteBuffer buffer):将数据写到Channel中,如果Channel中没有可写空间会一直堵塞到可写
  • write(ByteBuffer buffer, Long timeout):将数据写到Channel中,超过时间会报错
  • flush():将Channel中缓冲区数据刷到底层设备
  • register(Selector selector, SelectionKey key):将Channel注册到Selector
  • configureBlocking(boolean b):设置Channel是否为阻塞模式
  • socket():获取底层的Socket对象
  • isConnected():Channel是否已经连接上
  • isReadable():Channel是否可读
  • isWriteable():Channel是否可写
  • getRemoteAddress():Channel对应的远程地址
  • getLocalAddress():Channel对应的本地地址
  • open():Channel是否打开

2.2 Buffer

Buffer:缓冲读写数据,每一个Buffer对象关联一个字节数组。
在这里插入图片描述

2.2.1 常见的 Buffer

  • ByteBuffer
  • CharBuffer
  • ShortBuffer
  • IntBuffer
  • LongBuffer
  • FloatBuffer
  • DoubleBuffer

2.2.2 重要属性

  • capacity:Buffer所占的内存大小,设置后不能修改
  • limit:Buffer中可以操作的数据大小
  • position:下一个要读/写的数据索引
  • mark:标记当前position的位置,可以通过reset()position恢复到mark位置

2.2.3 常用方法

  • capacity():返回capacity的值
  • limit():返回limit的值
  • limit(int n):设置limit的值
  • position():返回position的值
  • position(int n): 设置position的值
  • mark():对Buffer做标记
  • reset():把position恢复到mark位置
  • rewind():设置position为0,取消mark标记
  • hasRemaining():判断Buffer中是否有元素
  • get():从Buffer中读取一个字节
  • get(byte[] b):从Buffer中读取多个字节
  • get(int index):从Buffer中读取指定索引位的字节
  • put(byte b):往Buffer中存一个字节
  • put(byte[] b):往Buffer中存多个字节
  • put(int index, byte b):往Buffer指定索引位存字节
  • clear():清空Buffer
  • compact():清空position之前的字节
  • flip():将limit设置为position的值,position设置为0

2.3 Selector

Selector配合一个线程管理多个Channel,获取Channel上发生的事件

2.3.1 四种事件类型

  • OP_CONNECT:连接成功后(只客户端使用)
  • OP_ACCEPT:客户端请求连接时(只服务端使用)
  • OP_READ:读缓冲区有可读数据时
  • OP_WRITE:写缓冲区有可写空间时
    在这里插入图片描述
package com.learn.wesay;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.nio.charset.StandardCharsets;
import java.util.Iterator;public class Server {public static void main(String[] args) throws IOException {// 创建Selector管理多个ChannelSelector selector = Selector.open();// 创建服务端套接字通道ServerSocketChannel server = ServerSocketChannel.open();// 设置为非阻塞server.configureBlocking(false);// 绑定端口server.bind(new InetSocketAddress(8888));// Channel注册到Selector,只处理accept事件server.register(selector, SelectionKey.OP_ACCEPT);while (true) {// 没有事件发生线程阻塞,有事件线程才会恢复运行selector.select();// 所有发生的事件Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();while (iterator.hasNext()) {SelectionKey selectionKey = iterator.next();if (selectionKey.isAcceptable()) {handlerAccept(selectionKey, selector);}if (selectionKey.isReadable()) {handlerRead(selectionKey, selector);}iterator.remove();}}}private static void handlerAccept(SelectionKey selectionKey, Selector selector) {ServerSocketChannel server = (ServerSocketChannel) selectionKey.channel();try {SocketChannel channel = server.accept();channel.configureBlocking(false);channel.register(selector, SelectionKey.OP_READ);System.out.println(channel);} catch (IOException e) {throw new RuntimeException(e);}}private static void handlerRead(SelectionKey selectionKey, Selector selector) {SocketChannel channel = (SocketChannel) selectionKey.channel();ByteBuffer byteBuffer = ByteBuffer.allocate(1024);try {int read = channel.read(byteBuffer);if (read == -1) {// 客户端socket正常断开selectionKey.cancel();} else {byteBuffer.flip();System.out.println(StandardCharsets.UTF_8.decode(byteBuffer));}} catch (IOException e) {// 客户端socket异常断开selectionKey.cancel();}}
}
public class Client {public static void main(String[] args) throws IOException {SocketChannel socketChannel = SocketChannel.open();socketChannel.connect(new InetSocketAddress("localhost", 8888));socketChannel.write(Charset.defaultCharset().encode("你好"));}
}

相关文章:

  • 使用DockerFile 编写 指令来构建镜像
  • continue插件二次开发调试并打包
  • notepad++ 批量转所有文件编码格式为UTF-8
  • c++中的constexpr 与decltype
  • 5.23 学习总结
  • Python KMP算法
  • 前端常用网站合集
  • 【cocos creator】进度条控制脚本,支持节点进度条,图片进度条,进度条组件,和进度文字展示
  • AI整体架构设计4:理解AI云原生
  • 活动预告|来 GIAC 大会听大数据降本利器:AutoMQ 基于云原生重新设计的 Kafka
  • 92.网络游戏逆向分析与漏洞攻防-游戏技能系统分析-利用哈希表实现快速读取文本内容
  • Typescript高级: 深入理解工厂函数类型
  • 【计算机毕业设计】基于SSM++jsp的实验室耗材管理系统【源码+lw+部署文档】
  • Day02:LeedCode977. 有序数组的平方 209.长度最小的子数组 59.螺旋矩阵II
  • 《Qt》使用Windeployqt发布程序
  • 2018一半小结一波
  • Docker: 容器互访的三种方式
  • ES2017异步函数现已正式可用
  • iBatis和MyBatis在使用ResultMap对应关系时的区别
  • iOS | NSProxy
  • jdbc就是这么简单
  • Linux中的硬链接与软链接
  • mysql innodb 索引使用指南
  • PHP 使用 Swoole - TaskWorker 实现异步操作 Mysql
  • Service Worker
  • SpiderData 2019年2月13日 DApp数据排行榜
  • text-decoration与color属性
  • XML已死 ?
  • 关于 Cirru Editor 存储格式
  • 力扣(LeetCode)22
  • 聊一聊前端的监控
  • 猫头鹰的深夜翻译:Java 2D Graphics, 简单的仿射变换
  • 详解NodeJs流之一
  • const的用法,特别是用在函数前面与后面的区别
  • FaaS 的简单实践
  • TPG领衔财团投资轻奢珠宝品牌APM Monaco
  • #我与Java虚拟机的故事#连载09:面试大厂逃不过的JVM
  • (1)Map集合 (2)异常机制 (3)File类 (4)I/O流
  • (2021|NIPS,扩散,无条件分数估计,条件分数估计)无分类器引导扩散
  • (3)llvm ir转换过程
  • (4.10~4.16)
  • (函数)颠倒字符串顺序(C语言)
  • (九十四)函数和二维数组
  • (离散数学)逻辑连接词
  • (六)Hibernate的二级缓存
  • (入门自用)--C++--抽象类--多态原理--虚表--1020
  • (三)Hyperledger Fabric 1.1安装部署-chaincode测试
  • (十八)用JAVA编写MP3解码器——迷你播放器
  • (四)汇编语言——简单程序
  • ***通过什么方式***网吧
  • .net core 实现redis分片_基于 Redis 的分布式任务调度框架 earth-frost
  • .NET6 开发一个检查某些状态持续多长时间的类
  • .netcore 如何获取系统中所有session_如何把百度推广中获取的线索(基木鱼,电话,百度商桥等)同步到企业微信或者企业CRM等企业营销系统中...
  • .NET面试题(二)
  • .NET序列化 serializable,反序列化