原生JDK网络编程-NIO实战

原生JDK网络编程-NIO实战

1、Selector对象是通过调用静态工厂方法open()来实例化的,如下:

ini 复制代码
Selector Selector=Selector.open();

2、要实现Selector管理Channel,需要将channel注册到相应的Selector上,如下:

ini 复制代码
channel.configureBlocking(false);
SelectionKey key= channel.register(selector,SelectionKey,OP_READ);

通过调用通道的register()方法会将它注册到一个选择器上。与Selector一起使用时,Channel必须处于非阻塞模式下,否则将抛出IllegalBlockingModeException异常,这意味着不能将FileChannel与Selector一起使用,因为FileChannel不能切换到非阻塞模式,而套接字通道都可以。另外通道一旦被注册,将不能再回到阻塞状态,此时若调用通道的configureBlocking(true)将抛出BlockingModeException异常。

3、在实际运行中,我们通过Selector的select()方法可以选择已经准备就绪的通道(这些通道包含你感兴趣的的事件)。

下面是Selector几个重载的select()方法:

scss 复制代码
select():阻塞到至少有一个通道在你注册的事件上就绪了。

select(long timeout):和select()一样,但最长阻塞时间为timeout毫秒。

selectNow():非阻塞,立刻返回。

select()方法返回的int值表示有多少通道已经就绪,是自上次调用select()方法后有多少通道变成就绪状态。

一旦调用select()方法,并且返回值不为0时,则可以通过调用Selector的selectedKeys()方法来访问已选择键集合。

Set selectedKeys=selector.selectedKeys();

这个时候,循环遍历selectedKeys集中的每个键,并检测各个键所对应的通道的就绪事件,再通过SelectionKey关联的Selector和Channel进行实际的业务处理。

注意每次迭代末尾的keyIterator.remove()调用。Selector不会自己从已选择键集中移除SelectionKey实例。必须在处理完通道时自己移除,否则的话,下次该通道变成就绪时,Selector会再次将其放入已选择键集中。

SelectionKey

什么是SelectionKey

SelectionKey是一个抽象类,表示selectableChannel在Selector中注册的标识.每个Channel向Selector注册时,都将会创建一个SelectionKey。SelectionKey将Channel与Selector建立了关系,并维护了channel事件。

可以通过cancel方法取消键,取消的键不会立即从selector中移除,而是添加到cancelledKeys中,在下一次select操作时移除它.所以在调用某个key时,需要使用isValid进行校验.

SelectionKey类型和就绪条件

在向Selector对象注册感兴趣的事件时,JAVA NIO共定义了四种:OP_READ、OP_WRITE、OP_CONNECT、OP_ACCEPT(定义在SelectionKey中),分别对应读、写、请求连接、接受连接等网络Socket操作。

Buffer

Buffer用于和NIO通道进行交互。数据是从通道读入缓冲区,从缓冲区写入到通道中的。以写为例,应用程序都是将数据写入缓冲,再通过通道把缓冲的数据发送出去,读也是一样,数据总是先从通道读到缓冲,应用程序再读缓冲的数据。

缓冲区本质上是一块可以写入数据,然后可以从中读取数据的内存(其实就是数组)。这块内存被包装成NIO Buffer对象,并提供了一组方法,用来方便的访问该块内存。

capacity

作为一个内存块,Buffer有一个固定的大小值,也叫"capacity".你只能往里写capacity个byte、long,char等类型。一旦Buffer满了,需要将其清空(通过读数据或者清除数据)才能继续写数据往里写数据。

position

当你写数据到Buffer中时,position表示当前能写的位置。初始的position值为0。当一个byte、long等数据写到Buffer后, position会向前移动到下一个可插入数据的Buffer单元。position最大可为capacity -- 1.

当读取数据时,也是从某个特定位置读。当将Buffer从写模式切换到读模式,position会被重置为0. 当从Buffer的position处读取数据时,position向前移动到下一个可读的位置。

limit

在写模式下,Buffer的limit表示你最多能往Buffer里写多少数据。写模式下,limit等于Buffer的capacity。

当切换Buffer到读模式时, limit表示你最多能读到多少数据。因此,当切换Buffer到读模式时,limit会被设置成写模式下的position值。换句话说,你能读到之前写入的所有数据(limit被设置成已写数据的数量,这个值在写模式下就是position)

Buffer的分配

要想获得一个Buffer对象首先要进行分配。每一个Buffer类都有allocate方法(可以在堆上分配,也可以在直接内存上分配)。

分配48字节capacity的ByteBuffer的例子

ini 复制代码
ByteBuffer buf = ByteBuffer.allocate(48);

分配一个可存储1024个字符的CharBuffer:

ini 复制代码
CharBuffer buf = CharBuffer.allocate(1024);
相关推荐
thinktik5 分钟前
还在手把手教AI写代码么? 让你的AWS Kiro AI IDE直接读飞书需求文档给你打工吧!
后端·serverless·aws
老青蛙2 小时前
权限系统设计-用户设计
后端
echoyu.2 小时前
消息队列-初识kafka
java·分布式·后端·spring cloud·中间件·架构·kafka
yuluo_YX3 小时前
Go Style 代码风格规范
开发语言·后端·golang
David爱编程3 小时前
从 JVM 到内核:synchronized 与操作系统互斥量的深度联系
java·后端
彭于晏Yan3 小时前
SpringBoot优化树形结构数据查询
java·spring boot·后端
章丸丸3 小时前
Tube - Studio Videos
前端·后端
练习时长一年4 小时前
Spring事件监听机制(三)
java·后端·spring
2301_781392524 小时前
用spring框架实现简单的MVC业务
java·后端·spring