Java基础知识强化之IO流笔记72:NIO之 NIO核心组件(NIO使用代码示例)
1.Java NIO 由以下几个核心部分组成:
- Channels(通道)
- Buffers(缓冲区)
- Selectors(选择器)
虽然Java NIO 中除此之外还有很多类和组件,Channel,Buffer 和 Selector 构成了核心的API。其它组件,如Pipe和FileLock,只不过是与三个核心组件共同使用的工具类。
(1)Channel 和 Buffer
基本上,所有的 IO操作在NIO 中都从一个Channel 开始。Channel 有点像 流。 数据可以从Channel读到Buffer中,也可以从Buffer 写到Channel中。这里有个图示:
Channel和Buffer有好几种类型。
下面是JAVA NIO中的一些主要Channel的实现:
- FileChannel
- DatagramChannel
- SocketChannel
- ServerSocketChannel
正如你所看到的,这些通道涵盖了UDP 和 TCP 网络IO,以及文件IO。
与这些类一起的有一些有趣的接口,但为简单起见,我尽量在概述中不提到它们。本教程其它章节与它们相关的地方我会进行解释。
以下是Java NIO里主要的Buffer实现:
- ByteBuffer
- CharBuffer
- DoubleBuffer
- FloatBuffer
- IntBuffer
- LongBuffer
- ShortBuffer
这些Buffer覆盖了你能通过IO发送的基本数据类型:byte, short, int, long, float, double 和 char。
Java NIO 还有个 MappedByteBuffer,用于表示内存映射文件, 我也不打算在概述中说明。
(2)Selector
Selector允许单线程处理多个 Channel。如果你的应用打开了多个连接(通道),但每个连接的流量都很低,使用Selector就会很方便。例如,在一个聊天服务器中。
这是在一个单线程中使用一个Selector处理3个Channel的图示:
要使用Selector,得向Selector注册Channel,然后调用它的select()方法。这个方法会一直阻塞到某个注册的通道有事件就绪。一旦这个方法返回,线程就可以处理这些事件,事件的例子有如新连接进来,数据接收等。
2. NIO使用代码示例:
java NIO服务端和客户端代码实现,为了更好地理解java NIO,下面贴出服务端和客户端的简单代码实现:
服务端:
package com.himi.demo2; 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; /**
* NIO 服务端
*
* @author hebao
*/
public class NIOServer {
// 通道管理器
private Selector selector; /**
* 获得一个ServerSocket通道,并对该通道做一些初始化的工作
*
* @param port
* 绑定的端口号
* @throws IOException
*/
public void initServer(int port) throws IOException {
// 获得一个ServerSocket通道
ServerSocketChannel serverChannel = ServerSocketChannel.open();
// 设置通道为非阻塞
serverChannel.configureBlocking(false);
// 将该通道对应的ServerSocket绑定到port端口
serverChannel.socket().bind(new InetSocketAddress(port));
// 获得一个通道管理器
this.selector = Selector.open();
// 将通道管理器和该通道绑定,并为该通道注册SelectionKey.OP_ACCEPT事件,注册该事件后,
// 当该事件到达时,selector.select()会返回,如果该事件没到达selector.select()会一直阻塞。
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
} /**
* 采用轮询的方式监听selector上是否有需要处理的事件,如果有,则进行处理
*
* @throws IOException
*/
@SuppressWarnings("unchecked")
public void listen() throws IOException {
System.out.println("服务端启动成功!");
// 轮询访问selector
while (true) {
// 当注册的事件到达时,方法返回;否则,该方法会一直阻塞
selector.select();
// 获得selector中选中的项的迭代器,选中的项为注册的事件
Iterator ite = this.selector.selectedKeys().iterator();
while (ite.hasNext()) {
SelectionKey key = (SelectionKey) ite.next();
// 删除已选的key,以防重复处理
ite.remove();
// 客户端请求连接事件
if (key.isAcceptable()) {
ServerSocketChannel server = (ServerSocketChannel) key.channel();
// 获得和客户端连接的通道
SocketChannel channel = server.accept();
// 设置成非阻塞
channel.configureBlocking(false); // 在这里可以给客户端发送信息哦
channel.write(ByteBuffer.wrap(new String("向客户端发送了一条信息").getBytes()));
// 在和客户端连接成功之后,为了可以接收到客户端的信息,需要给通道设置读的权限。
channel.register(this.selector, SelectionKey.OP_READ); // 获得了可读的事件
} else if (key.isReadable()) {
read(key);
} } }
} /**
* 处理读取客户端发来的信息 的事件
*
* @param key
* @throws IOException
*/
public void read(SelectionKey key) throws IOException {
// 服务器可读取消息:得到事件发生的Socket通道
SocketChannel channel = (SocketChannel) key.channel();
// 创建读取的缓冲区
ByteBuffer buffer = ByteBuffer.allocate(10);
channel.read(buffer);
byte[] data = buffer.array();
String msg = new String(data).trim();
System.out.println("服务端收到信息:" + msg);
ByteBuffer outBuffer = ByteBuffer.wrap(msg.getBytes());
channel.write(outBuffer);// 将消息回送给客户端
} /**
* 启动服务端测试
*
* @throws IOException
*/
public static void main(String[] args) throws IOException {
NIOServer server = new NIOServer();
server.initServer(8000);
server.listen();
} }
客户端:
package com.himi.demo2; 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; /**
* NIO客户端
*
* @author hebao
*/
public class NIOClient {
// 通道管理器
private Selector selector; /**
* 获得一个Socket通道,并对该通道做一些初始化的工作
*
* @param ip
* 连接的服务器的ip
* @param port
* 连接的服务器的端口号
* @throws IOException
*/
public void initClient(String ip, int port) throws IOException {
// 获得一个Socket通道
SocketChannel channel = SocketChannel.open();
// 设置通道为非阻塞
channel.configureBlocking(false);
// 获得一个通道管理器
this.selector = Selector.open(); // 客户端连接服务器,其实方法执行并没有实现连接,需要在listen()方法中调
// 用channel.finishConnect();才能完成连接
channel.connect(new InetSocketAddress(ip, port));
// 将通道管理器和该通道绑定,并为该通道注册SelectionKey.OP_CONNECT事件。
channel.register(selector, SelectionKey.OP_CONNECT);
} /**
* 采用轮询的方式监听selector上是否有需要处理的事件,如果有,则进行处理
*
* @throws IOException
*/
@SuppressWarnings("unchecked")
public void listen() throws IOException {
// 轮询访问selector
while (true) {
selector.select();
// 获得selector中选中的项的迭代器
Iterator ite = this.selector.selectedKeys().iterator();
while (ite.hasNext()) {
SelectionKey key = (SelectionKey) ite.next();
// 删除已选的key,以防重复处理
ite.remove();
// 连接事件发生
if (key.isConnectable()) {
SocketChannel channel = (SocketChannel) key.channel();
// 如果正在连接,则完成连接
if (channel.isConnectionPending()) {
channel.finishConnect(); }
// 设置成非阻塞
channel.configureBlocking(false); // 在这里可以给服务端发送信息哦
channel.write(ByteBuffer.wrap(new String("向服务端发送了一条信息").getBytes()));
// 在和服务端连接成功之后,为了可以接收到服务端的信息,需要给通道设置读的权限。
channel.register(this.selector, SelectionKey.OP_READ); // 获得了可读的事件
} else if (key.isReadable()) {
read(key);
} } }
} /**
* 处理读取服务端发来的信息 的事件
*
* @param key
* @throws IOException
*/
public void read(SelectionKey key) throws IOException {
// 和服务端的read方法一样
} /**
* 启动客户端测试
*
* @throws IOException
*/
public static void main(String[] args) throws IOException {
NIOClient client = new NIOClient();
client.initClient("localhost", 8000);
client.listen();
} }
Java基础知识强化之IO流笔记72:NIO之 NIO核心组件(NIO使用代码示例)的更多相关文章
- Java基础知识强化之IO流笔记05:try...catch...finally包含的代码是运行期的
1. 代码示例: 上面看到的第13行: Date d = null;(这里必须初始化) 第14~20行使用try...catch...finally包含代码,这里的代码已经变成运行期代码.此时我们 ...
- Java基础知识强化之IO流笔记63:随机访问流RandomAccessFile
1. 随机访问流RandomAccessFile RandomAccessFile类不属于流,是Object类的子类.但它融合了InputStream和OutputStream的功能.支持对随机访问文 ...
- Java基础知识强化之IO流笔记36:InputStreamReader/OutputStreamWriter 复制文本文件案例
1. 需求:把当前项目目录下的a.txt内容复制到当前项目目录下的b.txt中. 数据源: a.txt -- 读取数据 -- 字符转换流 -- InputStreamReader 目的地: b.t ...
- Java基础知识强化之IO流笔记17:FileOutputStream构造方法使用
1. 可以参照之前写的笔记: Android(java)学习笔记167:Java中操作文件的类介绍(File + IO流) 2. FileOutputStream(常用的)构造方法: FileOu ...
- Java基础知识强化之IO流笔记83:NIO与IO
当学习了Java NIO和IO的API后,一个问题马上涌入脑海: 我应该何时使用IO,何时使用NIO呢?在本文中,我会尽量清晰地解析Java NIO和IO的差异.它们的使用场景,以及它们如何影响您的代 ...
- Java基础知识强化之IO流笔记71:NIO之 NIO的(New IO流)介绍
1. I/O 简介 I/O ( 输入/输出 ):指的是计算机与外部世界或者一个程序与计算机的其余部分的之间的接口.它对于任何计算机系统都非常关键,因而所有 I/O 的主体实际上是内置在操作系统中的. ...
- Java基础知识强化之IO流笔记68:Properties和IO流集合使用
1. Properties和IO流集合使用 这里的集合必须是Properties集合: public void load(Reader reader):把文件中的数据读取到集合中 public v ...
- Java基础知识强化之IO流笔记66:Properties的概述 和 使用(作为Map集合使用)
1. Properties的概述 Properties:属性集合类.是一个可以和IO流相结合使用的集合类. 该类主要用于读取以项目的配置文件(以.properties结尾的文件 和 xml文件). ...
- Java基础知识强化之IO流笔记64:合并流SequenceInputStream
1. SequenceInputStream合并流的概述: SequenceInputStream类可以将多个输入流串联在一起,合并为一个输入流,因此,该流也被称为合并流. 2. Sequence ...
随机推荐
- USB枚举过程(1)
总的过程 ① host检测到device,reset 获取设备描述符 host发获取设备描述符请求 ->setup ->data0 <-ack Divice 返回设备描述符 -> ...
- LightOJ 1236 Pairs Forming LCM (LCM 唯一分解定理 + 素数筛选)
http://lightoj.com/volume_showproblem.php?problem=1236 Pairs Forming LCM Time Limit:2000MS Memor ...
- HDU 5437 Alisha’s Party (优先队列模拟)
题意:邀请k个朋友,每个朋友带有礼物价值不一,m次开门,每次开门让一定人数p(如果门外人数少于p,全都进去)进来,当最后所有人都到了还会再开一次门,让还没进来的人进来,每次都是礼物价值高的人先进.最后 ...
- WIN7建立wifi热点及无法启动承载网络的解决办法
1,根据网络共享的方法,最简单莫过于利用Win7的虚拟网卡来做热点,而不用借助其他软件. 首先,用管理员身份打开CMD命令提示符,输入 netsh wlan set hostednet ...
- oracle 空值与 null
Oracle中的空字符串基本上是被当成空NULL来处理的,我们可以从下面的得到印证. select nvl('','NULL') from dual 返回 'NULL' select ...
- user is not in the sudoers file.This incident will be reported
我用普通用户ssk登陆,想让ssk成为拥有超级用户的权限的普通用户 开始提示输入密码错误 ,然后就这样了 解决方法如下: 1>.进入超级用户模式.也就是输入"su -", ...
- 快速界面:QML。
PyQt, QML,Qt Quick. QML: QML可以在脚本里创建图形对象,并且支持各种图形特效,以及状态机等,同时又能跟Qt写的C++代码进行方便的交互,使用起来非常方便. 功能性不能,此篇博 ...
- [效果]JS折叠菜单-使用方法 (Moo.Fx)
(从已经死了一次又一次终于挂掉的百度空间人工抢救出来的,发表日期2014-06-24) 用法: 1.添加JS库 CODE:<script src="prototype.lite.js& ...
- sql server2008评估期已过...问题
sql server2008评估期已过...问题 当打开sql server2008企业管理器的时候,出现报错“评估期已过.有关如何升级的测试版软件的信息.....” 工具/原料 sql serv ...
- Netty高并发原理
Netty是一个高性能 事件驱动的异步的非堵塞的IO(NIO)框架,用于建立TCP等底层的连接,基于Netty可以建立高性能的Http服务器.支持HTTP. WebSocket .Protob ...