NIO 源码分析(01) NIO 最简用法

Netty 系列目录(https://www.cnblogs.com/binarylei/p/10117436.html)

Java NIO 主要由三个部分组成:Channel、Buffer 和 Selector。在分析源码前最好对 NIO 的基本用法和 Linux NIO 在一个基本的了解。

  1. NIO 入门
  2. Linux NIO

本文会提供一个 NIO 最简使用示例,之后的源码分析都会基于该示例及其扩展进行。

一、服务端

public class Server implements Runnable {
public static void main(String[] args) {
new Thread(new Server(8765)).start();
} // 1 多路复用器(管理所有的通道)
private Selector selector;
// 2 建立缓冲区
private ByteBuffer readBuf = ByteBuffer.allocate(1024);
private ByteBuffer writeBuf = ByteBuffer.allocate(1024); public Server(int port) {
try {
//1. 获取多路复用器
this.selector = Selector.open(); //2. 获取服务器端通道
ServerSocketChannel ssChannel = ServerSocketChannel.open(); //3. 切换成非阻塞模式
ssChannel.configureBlocking(false); //4. 绑定端口号
ssChannel.bind(new InetSocketAddress(port)); //5. 把服务器通道注册到多路复用器上,并且监听阻塞事件
ssChannel.register(this.selector, SelectionKey.OP_ACCEPT); System.out.println("Server start, port :" + port);
} catch (IOException e) {
e.printStackTrace();
}
} public void run() {
while (true) {
try {
// 1. 阻塞到至少有一个通道在你注册的事件上就绪,返回的 int 值表示有多少通道已经就绪
int wait = selector.select();
if (wait == 0) continue; //2. 遍历多路复用器上已经准备就绪的通道
Iterator<SelectionKey> iterator = this.selector.selectedKeys().iterator();
while (iterator.hasNext()) {
SelectionKey key = iterator.next(); if (key.isValid()) {
if (key.isAcceptable()) {
// 3.1 如果为 accept 状态,就获取客户端通道并注册到selector上
this.accept(key);
} else if (key.isReadable()) {
// 3.2 如果为可读状态
this.read(key);
} else if (key.isWritable()) {
// 3.3 写数据
this.write(key);
}
} // 4. 注意必须在处理完通道时自己移除
iterator.remove();
}
} catch (IOException e) {
e.printStackTrace();
}
}
} private void write(SelectionKey key) {
//ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
//ssc.register(this.seletor, SelectionKey.OP_WRITE);
} private void read(SelectionKey key) {
try {
//1. 清空缓冲区旧的数据
this.readBuf.clear(); //2. 获取之前注册的socket通道对象
SocketChannel sChannel = (SocketChannel) key.channel(); //3. 读数据
int len = sChannel.read(this.readBuf);
if (len == -1) {
key.channel().close();
key.cancel();
return;
} //5 有数据则进行读取 读取之前要flip()复位
this.readBuf.flip();
byte[] bytes = new byte[this.readBuf.remaining()];
this.readBuf.get(bytes); System.out.println("Server : " + new String(bytes).trim());
//6. 可以写回给客户端数据
} catch (IOException e) {
e.printStackTrace();
} } private void accept(SelectionKey key) {
try {
//1. 获取服务通道ServerSocketChannel
ServerSocketChannel ssChannel = (ServerSocketChannel) key.channel(); //2. 获取客户端通道SocketChannel
SocketChannel sChannel = ssChannel.accept(); //3. 客户端通道SocketChannel也要设置成非阻塞模式
sChannel.configureBlocking(false); //4 注册到多路复用器上,并设置读取标识
sChannel.register(this.selector, SelectionKey.OP_READ);
} catch (IOException e) {
e.printStackTrace();
}
}
}

二、客户端

public static void main(String[] args) throws IOException {
SocketChannel sChannel = null;
try {
//1. 获取通道
sChannel = SocketChannel.open(
new InetSocketAddress("127.0.0.1", 8765)); //2. 切换成非阻塞模式
sChannel.configureBlocking(false); //3. 分配缓冲区
ByteBuffer buf = ByteBuffer.allocate(1024); //4. 把从控制台读到数据发送给服务器端
Scanner scanner = new Scanner(System.in);
while (true) {
String str = scanner.next();
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
buf.put((dateFormat.format(new Date()) + ":" + str).getBytes());
buf.flip();// 非阻塞模式下,write()方法在尚未写出任何内容时可能就返回了
while (buf.hasRemaining()) {
sChannel.write(buf);
}
buf.clear();
}
} finally {
sChannel.close();
}
}

ok,完成!!!


每天用心记录一点点。内容也许不重要,但习惯很重要!

NIO 源码分析(01) NIO 最简用法的更多相关文章

  1. NIO 源码分析(02-2) BIO 源码分析 Socket

    目录 一.BIO 最简使用姿势 二.connect 方法 2.1 Socket.connect 方法 2.2 AbstractPlainSocketImpl.connect 方法 2.3 DualSt ...

  2. NIO 源码分析(02-1) BIO 源码分析

    目录 一.BIO 最简使用姿势 二.ServerSocket 源码分析 2.1 相关类图 2.2 主要属性 2.3 构造函数 2.4 bind 方法 2.5 accept 方法 2.6 总结 NIO ...

  3. NIO 源码分析(05) Channel 源码分析

    目录 一.Channel 类图 二.begin 和 close 是什么 2.1 AbstractInterruptibleChannel 中的 begin 和 close 2.2 Selector 中 ...

  4. NIO 源码分析(04) 从 SelectorProvider 看 JDK SPI 机制

    目录 一.SelectorProvider SPI 二.SelectorProvider 加载过程 2.1 SelectorProvider 加载 2.2 Windows 下 DefaultSelec ...

  5. NIO 源码分析(03) 从 BIO 到 NIO

    目录 一.NIO 三大组件 Channels.Buffers.Selectors 1.1 Channel 和 Buffer 1.2 Selector 1.3 Linux IO 和 NIO 编程的区别 ...

  6. 一个由正则表达式引发的血案 vs2017使用rdlc实现批量打印 vs2017使用rdlc [asp.net core 源码分析] 01 - Session SignalR sql for xml path用法 MemCahe C# 操作Excel图形——绘制、读取、隐藏、删除图形 IOC,DIP,DI,IoC容器

    1. 血案由来 近期我在为Lazada卖家中心做一个自助注册的项目,其中的shop name校验规则较为复杂,要求:1. 英文字母大小写2. 数字3. 越南文4. 一些特殊字符,如“&”,“- ...

  7. NIO源码分析:SelectionKey

    SelectionKey SelectionKey,选择键,在每次通道注册到选择器上时都会创建一个SelectionKey储存在该选择器上,该SelectionKey保存了注册的通道.注册的选择器.通 ...

  8. [asp.net core 源码分析] 01 - Session

    1.Session文档介绍 毋庸置疑学习.Net core最好的方法之一就是学习微软.Net core的官方文档:https://docs.microsoft.com/zh-cn/aspnet/cor ...

  9. dubbo源码分析01:SPI机制

    一.什么是SPI SPI全称为Service Provider Interface,是一种服务发现机制,其本质是将接口实现类的全限定名配置在文件中,并由服务加载器读取配置文件.这样可以在运行时,动态为 ...

随机推荐

  1. laravel生成key

    安装laravel之后要设置一个随即字符串作为应用密钥(key),如果你是通过composer或者laravel安装器安装的 这个key已经自动生成并设置了. 一般情况下这个key为32位长度字符串. ...

  2. Oracle高水位线(HWM)及性能优化

    说到HWM,我们首先要简要的谈谈ORACLE的逻辑存储管理.我们知道,ORACLE在逻辑存储上分4个粒度:表空间,段,区和块.    (1)块:是粒度最小的存储单位,现在标准的块大小是8K,ORACL ...

  3. es+mongodb 整合

    之前公司项目的数据都是从mysql查询,后面需求变更:同时技术上相应的也要改变策略,决定将mongodb和mysql的数据通过es建立索引来查询: 对于还没有接触或者真正了解es的可以先看一下相关Lu ...

  4. 函数高阶(函数,改变函数this指向,高阶函数,闭包,递归)

    一.函数的定义方式 1.函数声明方式 function  关键字(命名函数) 2.函数表达式(匿名函数) 3.new  Function( ) var  fn = new  Function(‘参数1 ...

  5. LeetCode Array Easy 122. Best Time to Buy and Sell Stock II

    Description Say you have an array for which the ith element is the price of a given stock on day i. ...

  6. Java的枚举类型使用方法详解

    1.背景在java语言中还没有引入枚举类型之前,表示枚举类型的常用模式是声明一组具有int常量.之前我们通常利用public final static 方法定义的代码如下,分别用1 表示春天,2表示夏 ...

  7. 2019-9-2-C#委托

    title author date CreateTime categories C#委托 lindexi 2019-09-02 12:57:37 +0800 2018-2-13 17:23:3 +08 ...

  8. Linux解压rar文件

    Linux解压rar文件(unrar安装和使用,分卷解压) windows平台很多压缩文档为rar文件,那么怎么做到Linux解压rar文件(unrar安装和使用)? 简单,centos5安装unra ...

  9. 死磕Spring源码系列

    一.Spring总体架构 1.架构图 2.SpringIOC:核心容器提供 Spring 框架的基本功能.核心容器的主要组件是 BeanFactory,它是工厂模式的实现.BeanFactory 使用 ...

  10. 【CSS】input 框的一些事情

    1.input框光标太长与不居中的问题 如果input框height:40px 为了字体垂直居中line-height也设为40px 问题来了,这样光标在刚刚focus时候是占据整个input框并且输 ...