netty权威指南第二章——NIO

NIO编程

2.3.1 NIO类库简介

2.3.1.1 缓存区
  • ByteBuffer:字节缓冲区
  • CharBuffer:字符缓冲区
  • ShortBuffer:短整型缓冲区
  • IntBuffer:整形缓冲区
  • LongBuffer:长整形缓冲区
  • FloatBuffer:浮点型缓冲区
  • DoubleBuffer:双精度浮点型缓冲区

继承关系:
在这里插入图片描述
每 一 个 Buffer 类 都 是 Buffer 接 口 的 一 个 了 实 例 。 除 了 ByteBuffer , 每 一 个 Buffer 都有 完 全 一 样 的 操 作 , 只 是 它 们 所 处 理 的 数 据 类 型 不 一 样 。 因 为 大 多 数 标 准 I / O 操 作 都 使 用ByteBuffer, 所 以 它 在 具 有 一 般 缓 冲 区 的 操 作 之 外 还 提 供 了 一 些 特 有 的 操 作 , 以 方 便 网 络读 写 。

2.3.1.2 通道 Channel

因 为 Channel 是 全 双 工 的 , 所 以 它 可 以 比 流 更 好 地 映 射 底 层 操 作 系 统 的 API。 特 别 是在 UNIX 网 络 编 程 模 型 中 , 底 层 操 作 系 统 的 通 道 都 是 全 双 工 的 , 同 时 支 持 读 写 操 作 。
在这里插入图片描述
自 顶 向 下 看 , 前 三 层 主 要 是 ChanneI 接 口 , 用 于 定 义 它 的 功 能 , 后 面 是 一 些 具 体 的 功能 类 ( 抽 象 类 从 类 图 可 以 看 出 , 实 际 上 ChanneI 可 以 分 为 两 大 类 : 用 于 网 络 读 写 的SelectableChannel 和 用 于 文 件 操 作 的 FileChannel。

2.3.1.3 多路复用器 Selector

在 本 节 中 , 我 们 将 探 索 多 路 复 用 器 selector , 它 是 JavaNlO 编 程 的 基 础 , 熟 练 地 掌 握SeIector 对 于 NIO 编 程 至 关 重 要 。 多 路 复 用 器 提 供 选 择 己 经 就 绪 的 任 务 的 能 力 。 简 单 来 讲 ,SeIector 会 不 断 地 轮 询 注 册 在 其 上 的 Channel , 如 果 某 个 Channel 上 面 发 生 读 或 者 写 事 件 ,这 个 Channel 就 处 于 就 绪 状 态 , 会 被 Selector 轮 询 出 来 , 然 后 通 过 SelectionKey 可 以 获 取就 绪 ChanneI 的 集 合 , 进 行 后 续 的 I/O 操 作 。

一 个 多 路 复 用 器 Selector 可 以 同 时 轮 询 多 个 Channel , 由 于 JDK 使 用 了 epoll() 代 替 传统 的 select 实 现 , 所 以 它 并 没 有 最 大 连 接 句 柄 1024 / 2048 的 限 制 。 这 也 就 意 味 着 只 需 要 一个 线 程 负 责 SeIector 的 轮 询 , 就 可 以 接 入 成 千 上 万 的 客 户 端 , 这 确 实 是 个 非 常 巨 大 的 进 步 。

2.3.2 NIO 服务端序列图

在这里插入图片描述
下 面 , 我 们 对 NIO 服 务 端 的 主 要 创 建 过 程 进 行 讲 解 和 说 明 , 作 为 NIO 的 基 础 入 门 ,这 里 将 忽 略 掉 一 些 在 生 产 环 境 中 部 署 所 需 要 的 特 性 和 功 能 。
步 骤 一 : 打 开 ServerSocketChanneI, 用 于 监 听 客 户 端 的 连 接 , 它 是 所 有 客 户 端 连 接 的
父 管 道 , 示 例 代 码 如 下 :
ServerSocketChannel acceptSvr = ServerSocketChannel.open();
步 骤 二 : 绑 定 监 听 端 口 , 设 置 连 接 为 非 咀 塞 模 式。

 acceptSvr.socket().bind(
                new InetSocketAddress(InetAddress.getByName("IP"),port));
        acceptSvr.configureBlocking(false);
步 骤 三 : 创 建 Reactor 线 程 , 创 建 多 路 复 用 器 并 启 动 线 程 , 示 例 代 码 如 下 。
Selector selector = Selector.open();
new Thread(new ReactorTask()).start();

步 骤 四 : 将 ServerSocketChannel 注 册 到 Reactor 线 程 的 多 路 复 用 器 SeIector 上 , 监 听
ACCEPT 事 件 , 示 例 代 码 如 下 。
SelectionKey key = acceptSvr.register(selector, SelectionKey.OP_ACCEPT, ioHandler);
步 骤 五 : 多 路 复 用 器 在 线 程 方 法 的 无 限 循 环 体 内 轮 询 准 备 就 绪 的 Key , 示 例 代 码

int num = selector.select();
        Set selectedKeys = selector.selectedKeys();
        Iterator it = selectedKeys.iterator();
        while (it.hasNext()){
            SelectionKey key = (SelectionKey) it.next();
            // ... deal with I/O event ...
        }

步 骤 六 : 多 路 复 用 器 监 听 到 有 新 的 客 户 端 接 入 , 处 理 新 的 接 入 请 求 , 完 成 TCP 三 次握 手 , 建 立 物 理 链 路 , 示 例 代 码 如 下 。
SocketChannel channel = acceptSvr.accept();
步 骤 七 : 设 置 客 户 端 链 路 为 非 阻 塞 模 式 , 示 例 代 码 如 下 。

channel.configureBlocking(false);
channel.socket().setReuseAddress(true);

步 骤 八 : 将 新 接 入 的 客 户 端 连 接 注 册 到 Reactor 线 程 的 多 路 复 用 器 上 , 监 听 读 操 作 ,读 取 客 户 端 发 送 的 网 络 消 息 , 示 例 代 码 如 下 :

SelectionKey key = socketChanne1.register( selector. Se1ectionKey.OP READ ,ioHand1er);

步 骤 九 : 异 步 读 取 客 户 端 请 求 消 息 到 缓 冲 区 , 示 例 代 码 如 下 。
int readNumber = channel.read (receivedBuffer) ;
步 骤 十 : 对 ByteBuffer 进 行 编 解 码 , 如 果 有 半 包 消 息 指 针 reset , 继 续 读 取 后 续 的 报 文 ,将 解 码 成 功 的 消 息 封 装 成 Task , 投 递 到 业 务 线 程 池 中 , 进 行 业 务 逻 辑 编 排 , 示 例 代 码 如 下 。

Object message = null;
while(buffer.hasRemain()){
	byteBuffer.mark();
	Object message = decode(byteBuffer);
	if(message==null){
		byteBuffer.reset();
		break;
	}
	messageList.add(message);
}

步 骤 十 一 : 将 POJO 对 象 encode 成 ByteBuffer , 调 用 SocketChanneI 的 异 步 write 接 口 ,将 消 息 异 步 发 送 给 客 户 端 , 示 例 代 码 如 下 。
socketChannel.write(buffer);

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值