Java NIO基本使用介绍
NIO主要包括Channel,Buffer,Selector三个核心元素组成。
Channel即通道,l和Buffer有好几种类型。下面是JAVA NIO中的一些主要Channel的实现:
- FileChannel
- DatagramChannel
- SocketChannel
- ServerSocketChannel
正如你所看到的,这些通道涵盖了UDP 和 TCP 网络IO,以及文件IO。
Buffer有IntBuffer,CharBuffer,FloatBuffer。。。。。
可以在Selector上注册通道。
Selector所在线程负责处理监听,待所关注的事件到达时,将事件分发给在Selector上注册的channel作异步处理,如下图所示。

Buffer的基本用法
使用Buffer读写数据一般遵循以下四个步骤:
- 调用channel的read()方法,将channel中的数据写入到Buffer中。
- 调用
flip()方法flip方法将Buffer从写模式切换到读模式。调用flip()方法会将position设回0,并将limit设置成之前position的值。
换句话说,position现在用于标记读的位置,limit表示之前写进了多少个byte、char等 —— 现在能读取多少个byte、char等。
public final Buffer flip() {
limit = position;
position = 0;
mark = -1;
return this;
} - 调用channel的write()方法,将Buffer中的数据写入channel中。
- 调用
clear()方法或者compact()方法
为了理解Buffer的工作原理,需要熟悉它的三个属性:
- capacity
- position
- limit
position和limit的含义取决于Buffer处在读模式还是写模式。不管Buffer处在什么模式,capacity的含义总是一样的。
这里有一个关于capacity,position和limit在读写模式中的说明,详细的解释在插图后面。

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)
使用JAVA NIO编写一个客户端与服务端通信的例子。
Server
package com.nio; import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set; public class Server {
private Selector selector;
private ByteBuffer readBuffer = ByteBuffer.allocate(100); public void start() throws IOException {
ServerSocketChannel ssc = ServerSocketChannel.open();
ssc.configureBlocking(false);
ssc.socket().bind(new InetSocketAddress("localhost", 8002));
selector = Selector.open();
ssc.register(selector, SelectionKey.OP_ACCEPT);
while (!Thread.currentThread().isInterrupted()) {
selector.select();
Set selectedKeys = selector.selectedKeys();
Iterator iterator = selectedKeys.iterator();
while (iterator.hasNext()) {
SelectionKey key = (SelectionKey) iterator.next();
if (!key.isValid()) {
continue;
}
if (key.isAcceptable()) {
accept(key);
} else if (key.isReadable()) {
read(key);
}
}
iterator.remove();
}
} private void read(SelectionKey key) throws IOException {
SocketChannel socketChannel = (SocketChannel) key.channel();
this.readBuffer.clear();
int readNum = 0;
try {
readNum = socketChannel.read(this.readBuffer);
} catch (IOException e) {
key.cancel();
socketChannel.close();
return;
}
if (readNum > 0) {
byte[] newBytes = new byte[readNum];
System.arraycopy(readBuffer.array(), 0, newBytes, 0, readNum);
String message = new String(newBytes);
System.out.println(message);
message = "你好,已收到你发的消息:" + message;
readBuffer.flip();
readBuffer = ByteBuffer.wrap(message.getBytes());
socketChannel.write(readBuffer);
}
} private void accept(SelectionKey key) throws IOException {
ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
SocketChannel clientChanel = ssc.accept();
clientChanel.configureBlocking(false);
clientChanel.register(selector, SelectionKey.OP_READ);
System.out.println("a new client connected...");
} public static void main(String[] args) throws IOException {
new Server().start();
}
}
Client
package com.nio; import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Scanner;
import java.util.Set; public class Client {
private void start() throws IOException {
SocketChannel sc = SocketChannel.open();
sc.configureBlocking(false);
sc.connect(new InetSocketAddress("localhost", 8002));
Selector selector = Selector.open();
sc.register(selector, SelectionKey.OP_CONNECT );
Scanner scanner = new Scanner(System.in);
while (true) {
selector.select();
Set selectedKeys = selector.selectedKeys();
Iterator iterator = selectedKeys.iterator();
while (iterator.hasNext()) {
SelectionKey key = (SelectionKey) iterator.next();
if (key.isConnectable()) {
sc.finishConnect();
sc.register(selector, SelectionKey.OP_WRITE);
System.out.println("server connected");
break;
} else if (key.isWritable()) {
System.out.println("please input message");
String message = scanner.nextLine();
ByteBuffer writebufBuffer = ByteBuffer.wrap(message.getBytes());
sc.write(writebufBuffer);
sc.register(selector, SelectionKey.OP_READ);
}else if(key.isReadable()){
ByteBuffer readBuffer = ByteBuffer.allocate(1024);
int readNum = sc.read(readBuffer);
byte[] newBytes = new byte[readNum];
System.arraycopy(readBuffer.array(), 0, newBytes, 0, readNum);
String message = new String(newBytes);
System.out.println(message);
sc.register(selector, SelectionKey.OP_WRITE);
}
}
iterator.remove();
}
} public static void main(String[] args) throws IOException {
new Client().start();
}
}
Client端输入abc后,Server端会将收到的信息返回到Client端,打印"你好,已收到......"

Server端也会打印出Client端发送的消息。

Java NIO基本使用介绍的更多相关文章
- 快学Java NIO 续篇
可以先看Java NIO的整体介绍,这篇接着说以下内容,<快学Java NIO>续篇 FileChannel SocketChannel ServerSocketChannel Java ...
- Java NIO简单介绍(二)
上一篇<NIO简单介绍(一)>中讲解了NIO中本地IO相关的内容,这篇重点介绍的NIO的非阻塞式网络通信 一.阻塞与非阻塞 传统的 IO 流都是阻塞式的.也就是说,当一个线程调用 read ...
- Java NIO简单介绍(一)
Java NIO( New IO) 是从Java 1.4版本开始引入的 一个新的IO API,可以替代标准的Java IO API. NIO与原来的IO有同样的作用和目的,但是使用的方式完全不同,NI ...
- java学习-NIO(五)NIO学习总结以及NIO新特性介绍
我们知道是NIO是在2002年引入到J2SE 1.4里的,很多Java开发者比如我还是不知道怎么充分利用NIO,更少的人知道在Java SE 7里引入了更新的输入/输出 API(NIO.2).但是对于 ...
- java NIO介绍
前言 我们在写java程序的时候,为了进行优化,把全部的精力用在了处理效率上,但是对IO的关注却很少.这也可能是由以前java早期时JVM在解释字节码时速度慢,运行速率大大低于本地编译代码,因此以前往 ...
- Java中NIO的简单介绍
NIO基本介绍 Java NIO(New IO) 也有人称之为Java non-blocking IO 是从Java1.4版本开始引入的一个新的IO API,可以代替标准的IO API.NIO与原来的 ...
- Java NIO框架Mina、Netty、Grizzly介绍与对比(zz)
Mina:Mina(Multipurpose Infrastructure for Network Applications) 是 Apache 组织一个较新的项目,它为开发高性能和高可用性的网络应用 ...
- [翻译] java NIO 教程---介绍
原文地址:http://tutorials.jenkov.com/java-nio/index.html Java NIO(new IO)是从java1.4之后的对IO API的另一种选择,即对标准j ...
- Java NIO框架Mina、Netty、Grizzly介绍与对比
Mina:Mina(Multipurpose Infrastructure for Network Applications) 是 Apache 组织一个较新的项目,它为开发高性能和高可用性的网络应用 ...
随机推荐
- NB-IoT知识
通常,我们把物联网设备分为三类: ①无需移动性,大数据量(上行),需较宽频段,比如城市监控摄像头. ②移动性强,需执行频繁切换,小数据量,比如车队追踪管理. ③无需移动性,小数据量,对时延不敏感,比如 ...
- NetScaler VPX在Azure上的部署(二)
本文是Citrix的工程师协助完成.主要是Citrix的VPX的配置. 导入License 进入NetScaler 中点击管理许可 导入后将有提示,请确认重启. 配置Azure HA 由于 ...
- vijos1779国王游戏
描述 恰逢H国国庆,国王邀请n位大臣来玩一个有奖游戏.首先,他让每个大臣在左.右手上面分别写下一个整数,国王自己也在左.右手上各写一个整数.然后,让这n位大臣排成一排,国王站在队伍的最前面.排好队后, ...
- [快手(AAuto)学习笔记]如何让程序在运行时请求管理员权限(UAC)
作者:ffsystem 作为(糟糕的)程序猿,习惯写代码解决一些简单事务.正常用批处理就能解决大部分工作,复杂一点用AutoIt 3. 有时候要分发给别人,就需要一个界面.外行你程序写得如何他看不懂, ...
- JavaScript代码存放位置
JavaScript代码存放位置 HTML的head中 HTML的body代码块底部(推荐) 由于Html代码是从上到下执行,如果Head中的js代码耗时严重,就会导致用户长时间无法看到页面,如果放置 ...
- Lua中的点、冒号与self
Lua中的点.冒号与self,它们之间的关系主要体现在函数的定义与调用上,Lua在函数定义时可以用点也可以用冒号,如: function mytable.fun(p) return p end fun ...
- 6、git和github
参考:http://www.cnblogs.com/qianmojing/p/6484162.htmlhttp://www.jb51.net/article/70729.htmhttp://www.c ...
- filter与servlet的比较
filter与servlet的比较 主要从如下四个方面介绍他们之间的区别: 1.概念. 2.生命周期. 3 ...
- 2. Web渗透测试中常见逻辑漏洞解析与实战
注:以下漏洞示例已由相关厂商修复,切勿非法测试! 0x01 漏洞挖掘 01 注册 注册中最常见的有两个,一个是恶意注册,另一个是账户遍历.一个好的注册界面应该是这样 或者这样的 而不是这样的 要么使 ...
- 没有定义json_encode()函数。
php5是没有json扩展的,需要自行下载. 命令php -m 可以查看安装了哪些扩展. 1.修改php.ini 在php.ini 中加入 extension=json.so:sudo vi /etc ...