原生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);
相关推荐
canonical_entropy31 分钟前
集成NopReport动态生成复杂Word表格
后端·低代码
come112341 小时前
Go 包管理工具详解:安装与使用指南
开发语言·后端·golang
绝无仅有1 小时前
OSS文件上传解析失败,错误:文件下载失败的排查与解决
后端·面试·架构
LaoZhangAI2 小时前
Kiro vs Cursor:2025年AI编程IDE深度对比
前端·后端
brzhang3 小时前
OpenAI 7周发布Codex,我们的数据库迁移为何要花一年?
前端·后端·架构
icecreamstorm4 小时前
预处理Statement
后端
轻语呢喃4 小时前
useReducer : hook 中的响应式状态管理
javascript·后端·react.js
陈随易4 小时前
MoonBit能给前端开发带来什么好处和实际案例演示
前端·后端·程序员
Qter4 小时前
RedHat7.5运行qtcreator时出现qt.qpa.plugin: Could not load the Qt platform plugin "xcb
前端·后端