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() 时,该线程被阻塞,直到有一些数据被读取或写入,该线程在 ...
随机推荐
- Python 进阶_OOP 面向对象编程_self 的实例绑定
目录 目录 self 和绑定 调用非绑定的方法 self 和绑定 在 Python 中 self 变量是特殊的, 其用于在实例方法中引用该方法所绑定的实例, 换句话说就是 Python 在实例化对象时 ...
- 关于之前提到的python开发restful风格的接口
此处不做详细说明. https://gitee.com/alin2017/my-i-demo.git 附上git地址,有兴趣的可以去clone一下. 里面针对代码都有相应的注释, 对于每一个文件也有r ...
- 数论---lcm和gcd
cd即最大公约数,lcm即最小公倍数. 首先给出a×b=gcd×lcm 证明:令gcd(a,b)=k,a=xk,b=yk,则a×b=xykk,而lcm=xyk,所以ab=gcd*lcm. 所以求lcm ...
- lua脚本分解字符串
--local str = "文字45 文字 789 文们adsd45 文字 wowo 文字 文字 wowo我们 wowo456 wiwo 465我们 456sdf 45 45我们adsd4 ...
- 数的直径(两次DFS)
题目传送门 桃花 题目描述 桃花一簇开无主,可爱深红映浅红. ——<题百叶桃花> 桃花长在桃树上,树的每个节 ...
- Https socket 连接
介: 本文主要介绍了网络安全通讯协议 SSL/TLS 和 Java 中关于安全通讯的实现部分.并通过一个简单的样例程序实现,来展示如何在 Java 平台上正确建立安全通讯. 在人类建立了通信系统之后, ...
- SQL数据库—<10>--查询练习题
待整理···· 45题.分页查询 学生选课数据库SQL语句练习题(45个题) 练习题网盘地址:点我 create database xxb go use xxb go --表(一)Student (学 ...
- html中代替空格、大于号、小于号等字符编码
数字表示法的不方便之处,在于必须知道每个字符的码点,很难记忆.为了能够快速输入,HTML 为一些特殊字符,规定了容易记忆的名字,允许通过名字来表示它们,这称为实体表示法(entity). 实体的写法是 ...
- NHibernet Unable to locate persister for the entity
第一 xml文件必须为 *.hbm.xml 第二 设置xml文件为嵌入的资源,用鼠标点击右键 然后生成操作里 选择嵌入的资源即可解决. https://www.cnblogs.com/lyj/
- 在脚本中使用set命令调试脚本
当脚本文件较长时,可以使用set命令指定调试一段脚本.在脚本中使用set -x命令开启调式模式:使用set +x命令关闭调式模式. 例如: #!/bin/bash #Scriptname: greet ...