ByteBuffer Test:

package java_guide;

import java.nio.ByteBuffer;

public class ByteBufferMethods {
public static void main(String[] args) {
//分配缓冲区(Allocating a Buffer)
ByteBuffer buffer = ByteBuffer.allocate(33);
System.out.println("--------Test reset----------");
//clear()方法,position将被设回0,limit被设置成 capacity的值
buffer.clear();
// 设置这个缓冲区的位置
buffer.position(5);
//将此缓冲区的标记设置在其位置。没有 buffer.mark();这句话会报错
buffer.mark();
buffer.position(10);
System.out.println("before reset:" + buffer);
//将此缓冲区的位置重置为先前标记的位置。(buffer.position(5))
buffer.reset();
System.out.println("after reset:" + buffer); System.out.println("--------Test rewind--------");
//position = 0;limit = capacity;mark = -1; 有点初始化的味道,但是并不影响底层byte数组的内容
buffer.clear();
buffer.position(10);
//返回此缓冲区的限制
buffer.limit(15);
System.out.println("before rewind:" + buffer);
//把position设为0,mark设为-1,不改变limit的值
buffer.rewind();
System.out.println("before rewind:" + buffer); System.out.println("--------Test compact--------");
buffer.clear();
buffer.put("abcd".getBytes());
System.out.println("before compact:" + buffer);
System.out.println(new String(buffer.array()));
//翻转就是将一个处于存数据状态的缓冲区变为一个处于准备取数据的状态 limit变为之前的position
buffer.flip();
System.out.println("after flip:" + buffer);
//get()方法:相对读,从position位置读取一个byte,并将position+1,为下次读写作准备
System.out.println((char) buffer.get());
System.out.println((char) buffer.get());
System.out.println((char) buffer.get());
System.out.println("after three gets:" + buffer);
System.out.println("\t" + new String(buffer.array()));
//把从position到limit中的内容移到0到limit-position的区域内,position和limit的取值也分别变成limit-position、capacity。
// 如果先将positon设置到limit,再compact,那么相当于clear()
buffer.compact();
System.out.println("after compact:" + buffer);
System.out.println("\t" + new String(buffer.array()));
System.out.println("------Test get-------------");
buffer = ByteBuffer.allocate(32);
buffer.put((byte) 'a').put((byte) 'b').put((byte) 'c').put((byte) 'd').put((byte) 'e').put((byte) 'f');
System.out.println("before flip()" + buffer); // 转换为读取模式
buffer.flip();
System.out.println("before get():" + buffer);
System.out.println((char) buffer.get());
System.out.println("after get():" + buffer);
// get(index)不影响position的值
System.out.println((char) buffer.get(2));
System.out.println("after get(index):" + buffer);
byte[] dst = new byte[10];
buffer.get(dst, 0, 2);
System.out.println("after get(dst, 0, 2):" + buffer);
System.out.println("\t dst:" + new String(dst));
System.out.println("buffer now is:" + buffer);
System.out.println("\t" + new String(buffer.array())); System.out.println("--------Test put-------");
ByteBuffer bb = ByteBuffer.allocate(32);
System.out.println("before put(byte):" + bb);
System.out.println("after put(byte):" + bb.put((byte) 'z'));
System.out.println("\t" + bb.put(2, (byte) 'c'));
// put(2,(byte) 'c')不改变position的位置
System.out.println("after put(2,(byte) 'c'):" + bb);
System.out.println("\t" + new String(bb.array()));
// 这里的buffer是 abcdef[pos=3 lim=6 cap=32]
bb.put(buffer);
System.out.println("after put(buffer):" + bb);
System.out.println("\t" + new String(bb.array()));
} }

输出:

--------Test reset----------
before reset:java.nio.HeapByteBuffer[pos=10 lim=33 cap=33]
after reset:java.nio.HeapByteBuffer[pos=5 lim=33 cap=33]
--------Test rewind--------
before rewind:java.nio.HeapByteBuffer[pos=10 lim=15 cap=33]
before rewind:java.nio.HeapByteBuffer[pos=0 lim=15 cap=33]
--------Test compact--------
before compact:java.nio.HeapByteBuffer[pos=4 lim=33 cap=33]
abcd
after flip:java.nio.HeapByteBuffer[pos=0 lim=4 cap=33]
a
b
c
after three gets:java.nio.HeapByteBuffer[pos=3 lim=4 cap=33]
abcd
after compact:java.nio.HeapByteBuffer[pos=1 lim=33 cap=33]
dbcd
------Test get-------------
before flip()java.nio.HeapByteBuffer[pos=6 lim=32 cap=32]
before get():java.nio.HeapByteBuffer[pos=0 lim=6 cap=32]
a
after get():java.nio.HeapByteBuffer[pos=1 lim=6 cap=32]
c
after get(index):java.nio.HeapByteBuffer[pos=1 lim=6 cap=32]
after get(dst, 0, 2):java.nio.HeapByteBuffer[pos=3 lim=6 cap=32]
dst:bc
buffer now is:java.nio.HeapByteBuffer[pos=3 lim=6 cap=32]
abcdef
--------Test put-------
before put(byte):java.nio.HeapByteBuffer[pos=0 lim=32 cap=32]
after put(byte):java.nio.HeapByteBuffer[pos=1 lim=32 cap=32]
java.nio.HeapByteBuffer[pos=1 lim=32 cap=32]
after put(2,(byte) 'c'):java.nio.HeapByteBuffer[pos=1 lim=32 cap=32]
z c
after put(buffer):java.nio.HeapByteBuffer[pos=4 lim=32 cap=32]
zdef

FileChannel Test:

package java_guide;

import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel; public class FileChannelTest {
public static void main(String[] args) {
RandomAccessFile raf;
try {
raf = new RandomAccessFile("D:\\workspace\\jian_zhi_offer\\src\\resource\\test.txt", "rw");
FileChannel inChannel = raf.getChannel();
ByteBuffer buffer = ByteBuffer.allocate(48);
int bytesRead = inChannel.read(buffer); ByteBuffer buffer2 = ByteBuffer.allocate(48);
buffer2.put("hello world\n".getBytes());
buffer2.flip();
inChannel.write(buffer2, 0);
while (bytesRead != -1) {
System.out.println("Reads:" + bytesRead);
buffer.flip();
while (buffer.hasRemaining()) {
System.out.print((char) buffer.get());
}
buffer.clear();
bytesRead = inChannel.read(buffer);
}
raf.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Reads:48
hello world
ldvvv
ddddddddddddd
fffffffffffffReads:44
fhello world
eeeeeeeeeeeeeeeeeeee
54654465

通过上述实例代码,我们可以大概总结出FileChannel的一般使用规则:

1. 开启FileChannel

使用之前,FileChannel必须被打开 ,但是你无法直接打开FileChannel(FileChannel是抽象类)。需要通过 InputStreamOutputStreamRandomAccessFile 获取FileChannel。

2. 从FileChannel读取数据/写入数据

从FileChannel中读取数据/写入数据之前首先要创建一个Buffer(缓冲区)对象,

3. 关闭FileChannel


C/S架构的channel:

package java_guide;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel; public class WebClient {
public static void main(String[] args) throws IOException {
SocketChannel socketChannel = SocketChannel.open();
socketChannel.connect(new InetSocketAddress("127.0.0.1", 3333));
ByteBuffer writeBuffer = ByteBuffer.allocate(128);
writeBuffer.put("hello this message is from client".getBytes());
writeBuffer.flip();
socketChannel.write(writeBuffer);
ByteBuffer readBuffer = ByteBuffer.allocate(128);
socketChannel.read(readBuffer);
StringBuffer stringBuffer = new StringBuffer();
readBuffer.flip();
while (readBuffer.hasRemaining()) {
stringBuffer.append((char) readBuffer.get());
}
System.out.println("从服务端接受到的数据:"+stringBuffer);
socketChannel.close();
}
}
package java_guide;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel; public class WebServer {
public static void main(String[] args) throws IOException {
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.socket().bind(new InetSocketAddress("127.0.0.1",3333));
SocketChannel socketChannel = serverSocketChannel.accept();
ByteBuffer writeBuffer = ByteBuffer.allocate(128);
writeBuffer.put("hello this is a message from server".getBytes());
writeBuffer.flip();
socketChannel.write(writeBuffer);
ByteBuffer readBuffer = ByteBuffer.allocate(128);
socketChannel.read(readBuffer);
StringBuffer stringBuffer = new StringBuffer();
readBuffer.flip();
while(readBuffer.hasRemaining()){
stringBuffer.append((char)readBuffer.get());
}
System.out.println("从客户端接收到的数据:"+stringBuffer);
socketChannel.close();
serverSocketChannel.close();
}
}

Selector(选择器)的使用方法介绍

1. Selector的创建

通过调用Selector.open()方法创建一个Selector对象,如下:

Selector selector = Selector.open();

2. 注册Channel到Selector

channel.configureBlocking(false);

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

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

  • Connect

  • Accept

  • Read

  • Write

通道触发了一个事件意思是该事件已经就绪。比如某个Channel成功连接到另一个服务器称为“ 连接就绪 ”。一个Server Socket Channel准备好接收新进入的连接称为“ 接收就绪”。一个有数据可读的通道可以说是“ 读就绪 ”。等待写数据的通道可以说是“ 写就绪 ”。

这四种事件用SelectionKey的四个常量来表示:

SelectionKey.OP_CONNECT

SelectionKey.OP_ACCEPT

SelectionKey.OP_READ

SelectionKey.OP_WRITE

如果你对不止一种事件感兴趣,使用或运算符即可,如下:int interestSet = SelectionKey.OP_READ | SelectionKey.OP_WRITE;

3. SelectionKey介绍

一个SelectionKey键表示了一个特定的通道对象和一个特定的选择器对象之间的注册关系。

key.attachment(); //返回SelectionKey的attachment,attachment可以在注册channel的时候指定。
key.channel(); // 返回该SelectionKey对应的channel。
key.selector(); // 返回该SelectionKey对应的Selector。
key.interestOps(); //返回代表需要Selector监控的IO操作的bit mask
key.readyOps(); // 返回一个bit mask,代表在相应channel上可以进行的IO操作。

三 模板代码

一个服务端的模板代码:

ServerSocketChannel ssc = ServerSocketChannel.open();
ssc.socket().bind(new InetSocketAddress("localhost", 8080));
ssc.configureBlocking(false);
Selector selector = Selector.open();
ssc.register(selector, SelectionKey.OP_ACCEPT);
while(true) {
int readyNum = selector.select();
if (readyNum == 0) {
continue;
} Set<SelectionKey> selectedKeys = selector.selectedKeys(); Iterator<SelectionKey> it = selectedKeys.iterator(); while(it.hasNext()) { SelectionKey key = it.next(); if(key.isAcceptable()) { // 接受连接 } else if (key.isReadable()) { // 通道可读 } else if (key.isWritable()) { // 通道可写 } it.remove(); }
}

参考:微信公众号

NIO理解的更多相关文章

  1. JAVA IO 以及 NIO 理解

    由于Netty,了解了一些异步IO的知识,JAVA里面NIO就是原来的IO的一个补充,本文主要记录下在JAVA中IO的底层实现原理,以及对Zerocopy技术介绍. IO,其实意味着:数据不停地搬入搬 ...

  2. Java NIO理解与使用

    https://blog.csdn.net/qq_18860653/article/details/53406723 Netty的使用或许我们看着官网user guide还是很容易入门的.因为java ...

  3. java NIO理解分析与基本使用

    我前段时间的一篇博客java网络编程--多线程数据收发并行总结了服务端与客户端之间的收发并行实践.原理很简单,就是针对单一客户端,服务端起两个线程分别负责read和write操作,然后线程保持阻塞等待 ...

  4. Java nio 理解

    Java nio 称为Java new IO ,对Java io而言的.他有两个主要的概念:缓存.通道. 在程序中,数据的来源或写入,要么网络.要么硬盘.所有通道分为:文件通道.TCP通道.UDP通道 ...

  5. 第十二章 NIO

    12.NIO 12.1 Java NIO 概述 1课时 12.2 Java NIO.2 之Path.Paths 与 Files 的使用 1课时 12.3 自动资源管理 1课时 12.4 缓冲区(Buf ...

  6. JAVA NIO 中的 zerocopy 技术提高IO性能

    关于一篇更详细更好的介绍 ZeroCopy技术的文章,可参考:JAVA IO 以及 NIO 理解 这篇文章介绍了 zerocopy技术来提高Linux平台上的IO密集型的JAVA应用程序的性能. ze ...

  7. netty使用从0到1

    本周强总在组内做了netty分享,内容相当不错,趁着这次分享记录的,以及以前研究,进行一下记录. java io形式存在三种,一种是BIO传统IO是阻塞IO,面向字符.字节服务都属于这一种.NIO官方 ...

  8. Netty学习路线

    预研时间170517-170519 投入时间:约10h 理解度:入门①前置基础:了解基本网络协议和通信方式[图解HTTP]http://download.csdn.net/detail/niehanm ...

  9. 关于CPU的User、Nice、System、Wait、Idle各个参数的解释

    使用Ganglia监控整个Hadoop集群,看到Ganglia采集的各种指标:CPU各个具体的指标含义解释如下: ①CPU(监测到的master主机上的CPU使用情况) 从图中看出,一共有五个关于CP ...

随机推荐

  1. 爬虫(七):爬取猫眼电影top100

    一:分析网站 目标站和目标数据目标地址:http://maoyan.com/board/4?offset=20目标数据:目标地址页面的电影列表,包括电影名,电影图片,主演,上映日期以及评分. 二:上代 ...

  2. 《论文翻译》 GIOU

    目录 广义交并比-GIOU(回归检测的一种指标和Loss) 注释 1. 摘要 2. 介绍 3. 相关工作 4. 广义交并比 5. GIOU作为目标检测的LOSS 6. 实验结果 7. 个人理解 单词汇 ...

  3. Ubuntu 14.04 indigo 安装 cartographer 1.0.0

    安装依赖(cmake 版本为2.8,我的是自带的)sudo apt-get updatesudo apt-get install -y g++ git google-mock libboost-all ...

  4. C++标准库分析总结(二)——<模板,分配器,List>

    本节主要总结模板及其类模板分类以及STL里面的分配器.容器内部结构以及容器之间的关系和分类,还介绍了容器中List的结构分布 1.源代码版本介绍 1.1 VC的编译器源码目录: 2.类模板 2.1 类 ...

  5. selenium鼠标操作

    #-*- coding:utf-8 -*- import time from selenium import webdriver from selenium.webdriver.common.acti ...

  6. Java基础系列 - 泛型和反射机制

    package com.test5; import java.lang.reflect.Field; import java.lang.reflect.Method; /** * Java泛型和反射机 ...

  7. nginx 转发 header 数据丢失

    刚帮同事解决了个问题,记录一下,现象:放在header里面的数据,本地后台可以收到,集成可以收到,测试不行, 查看代码没问题,排除代码问题,比较集成和测试环境有何不同,发现集成环境是局域网访问,192 ...

  8. 简记webpack运行报错 Uncaught TypeError: self.postMessage is not a function

    说好2017Fix的还是能重现,可能项目的版本比较旧了,简要记录解决办法 1.错误: index.js?bed3:67 Uncaught TypeError: self.postMessage is ...

  9. Hive和Hadoop

    我最近研究了hive的相关技术,有点心得,这里和大家分享下. 首先我们要知道hive到底是做什么的.下面这几段文字很好的描述了hive的特性: 1.hive是基于Hadoop的一个数据仓库工具,可以将 ...

  10. DES算法实现

    概述(团队项目) DES是一个分组加密算法,它以64位为分组对数据加密.同时DES也是一个对称算法:加密和解密用的是同一个算法.DES是一个包含16个阶段的"替换–置换"的分组加密 ...