NIO浅析(二)
一:前言
在(一中了解了NIO中的缓冲区和通道),通过本文章你会了解阻塞和非阻塞,选择器,管道
二:完成NIO通信的三要素
* 1.通道(Channel):负责连接
* java.nio.channels.Channel 接口:
* SelectableChannel
* //TCP
* SocketChannel
* ServerSocketChannel
* //UDP
* DatagramChannel
* Pipe.SinkChannel
* Pipe.SourceChannel
*
* 2.缓冲区:(Buffer):数据存取
* 3.选择器:(Selector):(是SelectableChannel的多路复用器)是用于监控SelectableChannel的IO状况
先使用阻塞式通信
客户端
//客户端
@Test
public void client() throws IOException {
//1.获取通道
SocketChannel sChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 9898));
FileChannel inChannel = FileChannel.open(Paths.get("1.jpg"), StandardOpenOption.READ);
//2.分配指定大小的缓冲区
ByteBuffer buf = ByteBuffer.allocate(1024);
//3.读取本地文件,并发送到服务端
while (inChannel.read(buf)!=-1){
buf.flip();
sChannel.write(buf);
buf.clear();
}
//关闭通道
inChannel.close();
sChannel.close();
}
服务端
//服务端
@Test
public void server() throws IOException {
//1.获取通道
ServerSocketChannel ssChannel = ServerSocketChannel.open();
FileChannel outChannel = FileChannel.open(Paths.get("4.jpg"), StandardOpenOption.WRITE, StandardOpenOption.CREATE); //2.绑定连接端口号
ssChannel.bind(new InetSocketAddress(9898));
//3.获取客户端的连接的通道
SocketChannel sChannel = ssChannel.accept();
//4.分配指定大小的缓冲区
ByteBuffer buf = ByteBuffer.allocate(1024);
//5.接受客户端的数据并保存到本地
while (sChannel.read(buf)!=-1){
buf.flip();
outChannel.write(buf);
buf.clear();
}
sChannel.close();
outChannel.close();
ssChannel.close(); }
阻塞式通信:当一个线程调用 read() 或 write()时,该线程被阻塞,直到有一些数据被读取或写入,该线程在此期间不能执行其他任务。因此,在完成网络通信进行 IO 操作时,由于线程会阻塞,所以服务器必须为每个客户端都提供一个独立的线程进行处理,当服务器端需要处理大量客户端时,性能急剧下降。
下面使用选择器完成非阻塞式通信(TCP)
客户端
//客户端
@Test
public void client() throws IOException {
//1.获取通道
SocketChannel sChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 9898));
//2.切换成非阻塞模式
sChannel.configureBlocking(false);
//3.分配指定大小的缓冲区
ByteBuffer buf = ByteBuffer.allocate(1024);
//4.发送数据到服务端
buf.put(new Date().toString().getBytes());
buf.flip();
sChannel.write(buf); //关闭通道
sChannel.close();
}
服务端
//服务端
@Test
public void server() throws IOException {
//1.获取通道
ServerSocketChannel ssChannel = ServerSocketChannel.open();
//2.切换到非阻塞模式
ssChannel.configureBlocking(false);
//3.绑定连接
ssChannel.bind(new InetSocketAddress(9898));
//4.获取选择器
Selector selector = Selector.open();
//5.将通道注册到选择器上
ssChannel.register(selector, SelectionKey.OP_ACCEPT);
//6.轮询式获取选择器上面已经“准备就绪的事件”
while(selector.select()>0){
//7.获取当前选择器中所有注册的“选择键(已就绪的监听事件)”
Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
while(iterator.hasNext()){
//8.获取就绪事件
SelectionKey sk = iterator.next();
//9.判断具体是什么事件准备就绪
if(sk.isAcceptable()){
//10.若“接收就绪”,获取客户端连接
SocketChannel sChannel = ssChannel.accept();
//11.切换到非阻塞模式
sChannel.configureBlocking(false); //12.将该通道注册到选择器上
sChannel.register(selector,SelectionKey.OP_READ);
}else if(sk.isReadable()){
//13.若读就绪,获取读就绪状态的通道
SocketChannel sChannel = (SocketChannel)sk.channel();
//14.读取数据
ByteBuffer buf = ByteBuffer.allocate(1024);
int len=0;
while((len=sChannel.read(buf))>0){
buf.flip();
System.out.println(new String(buf.array(),0,len));
buf.clear();
}
}
//取消选择键SelectionKey
iterator.remove();
}
}
}
非阻塞式通信:当线程从某通道进行读写数据时,若没有数据可用时,该线程可以进行其他任务。线程通常将非阻塞 IO 的空闲时间用于在其他通道上执行 IO 操作,所以单独的线程可以管理多个输入和输出通道。因此,NIO 可以让服务器端使用一个或有限几个线程来同时处理连接到服务器端的所有客户端。

再来一个例子(DatagramChannel)UDP
客户端
@Test
public void send() throws IOException {
//通道
DatagramChannel dChannel = DatagramChannel.open();
//设置为非阻塞
dChannel.configureBlocking(false);
//设置缓冲区
ByteBuffer buf = ByteBuffer.allocate(1024);
buf.put(new Date().toString().getBytes()); buf.flip();
dChannel.send(buf,new InetSocketAddress("127.0.0.1",9898)); dChannel.close();
}
服务端
@Test
public void receive() throws IOException {
DatagramChannel dChannel = DatagramChannel.open();
dChannel.configureBlocking(false);
dChannel.bind(new InetSocketAddress(9898)); Selector selector = Selector.open();
dChannel.register(selector, SelectionKey.OP_READ);
//6.轮询式获取选择器上面已经“准备就绪的事件”
while(selector.select()>0){
//7.获取当前选择器中所有注册的“选择键(已就绪的监听事件)”
Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
while(iterator.hasNext()){
//8.获取就绪事件
SelectionKey sk = iterator.next();
//9.判断具体是什么事件准备就绪
if(sk.isReadable()){
ByteBuffer buf = ByteBuffer.allocate(1024);
dChannel.receive(buf);
buf.flip();
System.out.println(new String(buf.array(),0,buf.limit()));
buf.clear();
}
//取消选择键SelectionKey
iterator.remove();
}
}
}
三:管道
2个线程之间的单向数据连接,管道有一个source通道和一个sink通道,数据写道sink通道,到source通道读取

@Test
public void test1() throws IOException {
//1.获取管道
Pipe pipe = Pipe.open();
//2.将缓冲区的数据写入管道
ByteBuffer buf = ByteBuffer.allocate(1024);
Pipe.SinkChannel sinkChannel = pipe.sink(); buf.put(new Date().toString().getBytes());
buf.flip();
sinkChannel.write(buf); //读取缓冲区里面的数据
Pipe.SourceChannel source = pipe.source();
buf.flip();
int len=source.read(buf);
System.out.println(new String(buf.array(),0,len)); source.close();
sinkChannel.close(); }
NIO浅析(二)的更多相关文章
- NIO(二、Buffer)
目录 NIO(一.概述) NIO(二.Buffer) Buffer 前文讲了NIO与IO的区别,那么这一章开始讲述NIO下核心类 - Buffer类 上一章就说过,NIO的核心包括三个部分:通道(Ch ...
- InnoDB的锁机制浅析(二)—探索InnoDB中的锁(Record锁/Gap锁/Next-key锁/插入意向锁)
Record锁/Gap锁/Next-key锁/插入意向锁 文章总共分为五个部分: InnoDB的锁机制浅析(一)-基本概念/兼容矩阵 InnoDB的锁机制浅析(二)-探索InnoDB中的锁(Recor ...
- EM算法浅析(二)-算法初探
EM算法浅析,我准备写一个系列的文章: EM算法浅析(一)-问题引出 EM算法浅析(二)-算法初探 一.EM算法简介 在EM算法之一--问题引出中我们介绍了硬币的问题,给出了模型的目标函数,提到了这种 ...
- java nio 通道(二)
本文章来源于我的个人博客: java nio 通道(二) 一,文件通道 文件通道总是堵塞式的,因此不能被置于非堵塞模式. FileChannel对象是线程安全的.多个进程能够在同一个实例上并发调用方法 ...
- Java NIO浅析 转至 美团技术团队
出处: Java NIO浅析 NIO(Non-blocking I/O,在Java领域,也称为New I/O),是一种同步非阻塞的I/O模型,也是I/O多路复用的基础,已经被越来越多地应用到大型应用服 ...
- 深入理解NIO(二)—— Tomcat中对NIO的应用
深入理解NIO(二)—— Tomcat中对NIO的应用 老哥行行好,转载和我说一声好吗,我不介意转载的,但是请把原文链接贴大点好吗 Tomcat大致架构 先贴两张图大致看一眼Tomcat的架构 Tom ...
- JAVA NIO学习二:通道(Channel)与缓冲区(Buffer)
今天是2018年的第三天,真是时光飞逝,2017年的学习计划还没有学习完成,因此继续开始研究学习,那么上一节我们了解了NIO,那么这一节我们进一步来学习NIO相关的知识.那就是通道和缓冲区.Java ...
- ReentrantLock和condition源码浅析(二)
转载请注明出处... 接着上一篇的ReentrantLock和condition源码浅析(一),这篇围绕着condition 一.condition的介绍 在这里为了作对比,引入Object类的两个方 ...
- Java基础——NIO(二)非阻塞式网络通信与NIO2新增类库
一.NIO非阻塞式网络通信 1.阻塞与非阻塞的概念 传统的 IO 流都是阻塞式的.也就是说,当一个线程调用 read() 或 write() 时,该线程被阻塞,直到有一些数据被读取或写入,该线程在 ...
随机推荐
- 抽象类 抽象方法 abstract
abstract: * abstract修饰类: 抽象类 * > 此类不能被实例化 * > 抽象类中一定要有构造器, 便于子类对象实例时调用(涉及子类对象实例化过程) * > 开发中 ...
- python分类预测模型的特点
python分类预测模型的特点 模型 模型特点 位于 SVM 强大的模型,可以用来回归,预测,分类等,而根据选取不同的和函数,模型可以是线性的/非线性的 sklearn.svm 决策树 基于" ...
- 仿移动端触摸滑动插件swiper,的简单实现
/** * @author lyj * @Date 2016-02-04 * @Method 滑动方法 针对一个大容器内部的容器做滑动封装 * @param * args args.swipeDo ...
- 【一起学源码-微服务】Nexflix Eureka 源码三:EurekaServer启动之EurekaServer上下文EurekaClient创建
前言 上篇文章已经介绍了 Eureka Server 环境和上下文初始化的一些代码,其中重点讲解了environment初始化使用的单例模式,以及EurekaServerConfigure基于接口对外 ...
- Cocos2d-x之Array
| 版权声明:本文为博主原创文章,未经博主允许不得转载. Array是一个列表类容器,是一种线性序列结构:列表容器中的元素是有序的,可以通过下标来访问,就和数组一样.其中Vector也是一种列表容 ...
- leetcode.排序.215数组中的第k个最大元素-Java
1. 具体题目 在未排序的数组中找到第 k 个最大的元素.请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素. 示例 : 输入: [3,2,1,5,6,4] 和 k = ...
- HDU 1398 Square Coins(DP)
Square Coins Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Tota ...
- 分布式ID的雪花算法及坑
分布式ID生成是目前系统的常见刚需,其中以Twitter的雪花算法(Snowflake)比较知名,有Java等各种语言的版本及各种改进版本,能生成满足分布式ID,返回ID为Long长整数 但是这里有一 ...
- vue - blog开发学7
将基本的项目部署到linux上(前后台只是实现了基本的功能,本次只是记录一些基本的开发流程,完善,等后续) 1.linux环境准备(我用的是阿里云服务器) ①jre.mysql,Nginx基本上这些就 ...
- SQL数据库—<8>触发器
触发器:一.什么是触发器? 一段SQL代码,挂到某个表的某个增.删.改的操作上. 当这个表执行相应的操作时,就会触发这段相应的SQL代码.触发器与存储过程的区别:1.存储过程是独立于表存在 ...