java nio 怎么用,Java NIO简单使用

前段时间在项目组分享了下NIO,现重新整理一下

一.概念

什么是NIO,和传统IO有什么区别:

java NIO全称java non-blocking IO,是指jdk1.4 及以上版本里提供的新api(New IO) ,为所有的原始类型(boolean类型除外)提供缓存支持的数据容器,使用它可以提供非阻塞式的高伸缩性网络。(百度百科)

主要区别

IO

NIO

面向流

缓冲区

阻塞

非阻塞

--

多路复用

阻塞IO和非阻塞IO

二.核心组件

Channels(通道)

Buffers(缓冲区)

Selectors(选择器)

三.Buffer(缓冲区)

Java NIO的Buffer用于和NIO通道进行交互,缓冲区本质上可以写入数据,读取数据的内存,这块内存被包装成Buffer对象

数据都是通过通道(Channel)读入缓冲区,从缓冲区写入通道

属性

Capacity(容量):缓冲区能够容纳的元素的最大数量,初始化时就被设定

Limit(上界) :缓冲区的第一个不能被读或写的元素(缓冲区中现存元素的个数)

Position(位置):下一个要被读或写的元素索引,位置会自动由get()和put()更新

Mark(标记):一个备忘位置

APi

put() 写数据

get() 读取

flip()翻转:将一个能够继续添加元素的缓冲区翻转成一个准备读出元素的释放状态

hasRemaining():函数会在释放缓冲区时告诉是否已经达到缓冲区的上界

clear 回到初始状态

mark()标记, reset()回滚

ByteBuffer.allocate(10); 创建 底层都是数组

ByteBuffer.allocateDirect(10); 创建 底层不是数组

wrap(new byte[10]); 传入byte数组,使用整个数组创建

wrap(new byte[10],2,3); 传入byte数组,使用数组部分创建

compact 将未读数据前移,positom指向前移后数据的后一位,limit = capacity;一次没有读完,切换到写模式

四.Channel(通道)

Java nio的通道类似流,但又有不同:既可以从通道中读取数据,又可以写数据到通道,但是流的读写通常时单向的通道可以异步去读写通道中的数据总是要先读到一个Buffer,或总是要从一个Buffer中写入

主要实现:

FileChannel : 从文件中读写数据

DatagramChannel: 通过UDP读写网络数据

SocketChannel:通过TCP读写网络数据

ServerSocketChannel:监听新进来的tcp连接

通道读是将数据从通道读到buffer里面;

通道写是将数据从buffer写入到通道;

五.selector(选择器)

选择器是java NIO中能够检测一道多个NIO通道,并能够知晓通道是否为读写事件做好准备的组件一个单独的线程可以管理多个channel

selector使用:

创建selector

Selector selector = Selector.open();

注册channel到selector

channel.configureBlocking(false);

SelectionKey key = channel.register(selector,SelectionKey.OP_READ );

与Selector一起使用时,Channel必须处于非阻塞模式下。这意味着不能将 FileChannel与Selector一起使用,因为FileChannel不能切换到非阻塞模式。而套接字通道都可以。

通道选择

int count = selector.select();

访问“已选择键集(selected key set)”中的就绪通道

Set selectedKeys = selector.selectedKeys();

注意register()方法的第二个参数。这是一个“interest集合”,意思是在通过Selector监听Channel时对什么事件感兴趣。可以监听四种不同类型的事件:

1. Connect

2. Accept

3. Read

4. Write

SelectionKeys

属性

slector() 获取对象本身

channel() 获取当前就绪的通道

cancel() 取消注册事件(通道)

interst(int ops)注册感兴趣事件

attachment() 附加对象

5ee62bf85b32

image.png

/**

* @ClassName NioServer

* @Description TODO

* @Author liuzetian

* @Date 2019/5/5 17:55 PM

* @Version 1.0

**/

public class NioServer {

private static Selector selector;

private static ServerSocketChannel serverSocketChannel;

private static ByteBuffer bf = ByteBuffer.allocate(1024);

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

//创建selector

selector = Selector.open();

//打开serverSocketChannel通道

serverSocketChannel = ServerSocketChannel.open();

//设置为非阻塞模式

serverSocketChannel.configureBlocking(false);

//开启绑定端口

serverSocketChannel.socket().bind(new InetSocketAddress(8080));

//向selector注册

serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

while (true) {

//count为准备就绪通道的数量 阻塞

int count = selector.select();

//已选择键集

Iterator it = selector.selectedKeys().iterator();

//遍历

while (it.hasNext()) {

SelectionKey key = it.next();

//连接状态

if (key.isAcceptable()) {

System.out.println("新连接进入");

ServerSocketChannel server = (ServerSocketChannel) key.channel();

SocketChannel channel = server.accept();

channel.configureBlocking(false);

channel.register(selector, SelectionKey.OP_READ);

} else if (key.isReadable()) {

//数据可读状态

System.out.println("读准备就绪,开始读.......................");

//获取SocketChannel 读取数据

SocketChannel channel = (SocketChannel) key.channel();

System.out.println("客户端的数据如下:");

int readLen = 0;

bf.clear();

StringBuffer sb = new StringBuffer();

//注意一定要读取完数据然后关闭通道,

while ((readLen = channel.read(bf)) > 0) {

bf.flip();

byte[] temp = new byte[readLen];

bf.get(temp, 0, readLen);

sb.append(new String(temp));

bf.clear();

}

if (-1 == readLen) {

channel.close();

}

System.out.println(sb.toString());

//注册写事件

channel.register(selector, SelectionKey.OP_WRITE);

} else if (key.isWritable()) {

//写事件

SocketChannel channel = (SocketChannel) key.channel();

channel.write(ByteBuffer.wrap(("客户端,已接收到传送来的数据").getBytes()));

//注销写事件

key.cancel();

// channel.close();

}

it.remove();

}

}

}

}

介绍的比较简单, 如有错误, 欢迎指正

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值