NIO理解
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是抽象类)。需要通过 InputStream , OutputStream 或 RandomAccessFile 获取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理解的更多相关文章
- JAVA IO 以及 NIO 理解
由于Netty,了解了一些异步IO的知识,JAVA里面NIO就是原来的IO的一个补充,本文主要记录下在JAVA中IO的底层实现原理,以及对Zerocopy技术介绍. IO,其实意味着:数据不停地搬入搬 ...
- Java NIO理解与使用
https://blog.csdn.net/qq_18860653/article/details/53406723 Netty的使用或许我们看着官网user guide还是很容易入门的.因为java ...
- java NIO理解分析与基本使用
我前段时间的一篇博客java网络编程--多线程数据收发并行总结了服务端与客户端之间的收发并行实践.原理很简单,就是针对单一客户端,服务端起两个线程分别负责read和write操作,然后线程保持阻塞等待 ...
- Java nio 理解
Java nio 称为Java new IO ,对Java io而言的.他有两个主要的概念:缓存.通道. 在程序中,数据的来源或写入,要么网络.要么硬盘.所有通道分为:文件通道.TCP通道.UDP通道 ...
- 第十二章 NIO
12.NIO 12.1 Java NIO 概述 1课时 12.2 Java NIO.2 之Path.Paths 与 Files 的使用 1课时 12.3 自动资源管理 1课时 12.4 缓冲区(Buf ...
- JAVA NIO 中的 zerocopy 技术提高IO性能
关于一篇更详细更好的介绍 ZeroCopy技术的文章,可参考:JAVA IO 以及 NIO 理解 这篇文章介绍了 zerocopy技术来提高Linux平台上的IO密集型的JAVA应用程序的性能. ze ...
- netty使用从0到1
本周强总在组内做了netty分享,内容相当不错,趁着这次分享记录的,以及以前研究,进行一下记录. java io形式存在三种,一种是BIO传统IO是阻塞IO,面向字符.字节服务都属于这一种.NIO官方 ...
- Netty学习路线
预研时间170517-170519 投入时间:约10h 理解度:入门①前置基础:了解基本网络协议和通信方式[图解HTTP]http://download.csdn.net/detail/niehanm ...
- 关于CPU的User、Nice、System、Wait、Idle各个参数的解释
使用Ganglia监控整个Hadoop集群,看到Ganglia采集的各种指标:CPU各个具体的指标含义解释如下: ①CPU(监测到的master主机上的CPU使用情况) 从图中看出,一共有五个关于CP ...
随机推荐
- springboot启动时执行任务CommandLineRunner
# SpringBoot中CommandLineRunner的作用> 平常开发中有可能需要实现在项目启动后执行的功能,SpringBoot提供的一种简单的实现方案就是添加一个model并实现Co ...
- 炸掉的fft,改天再调
#include <iostream> #include <cstdio> #include <cmath> #include <algorithm> ...
- linux系列(十八):locate命令
1.命令格式: locate [选择参数] [样式] 2.命令功能: locate指令和find找寻档案的功能类似,但locate是透过update程序将硬盘中的所有档案和目录资料先建立一个索引数据库 ...
- Luogu5072 [Ynoi2015]盼君勿忘 【莫队】
题目描述:对于一个长度为\(n\)的序列,\(m\)次询问\(l,r,p\),计算\([l,r]\)的所有子序列的不同数之和\(\mathrm{mod} \ p\). 数据范围:\(n,m,a_i\l ...
- codeforces193B
CF193B Xor sol:发现好像非常不可做的样子,发现n,u都很小,大胆dfs,因为异或偶数次毫无卵用,只要判每次是否做2操作就是了,复杂度O(可过) #include <bits/std ...
- WPF_AutoCompleteBox智能提示_Xml读写
效果图 1.需要引用的DLL 2. Window.xaml <Window x:Class="自己的命名空间" xmlns="http://schemas.micr ...
- Java基础系列 - 数组、二维数组、对象数组
package com.test2; public class demo2 { public static void main(String[] args) { /** * 一维数组使用 */ //数 ...
- linux ssh终端解决中文乱码的问题
@1:第一种办法: 在linux服务器里 命令行修改Linux服务器文件: vi /etc/sysconfig/i18n 默认的内容为: LANG="zh_CN.UTF-8" ; ...
- 【python代码】linux 登陆网关
#!/usr/bin/env python import urllib2 url="http://10.3.8.211" data="DDDDD=2010111222&a ...
- 【原】Python基础-字典
字典是Python唯一内建的映射类型.键可以是数字,字符串和元组. 1 字典的创建 方法一:直接创建 例如: >>> dict = {'key1':'value1', 20: 80} ...