Java-NIO之Channel(通道)
1:Channel是什么
通道表示与实体的开放连接,例如硬件设备、文件、网络套接字或能够执行一个或多个不同 I/O 操作(例如读取或写入)的程序组件。
1.1:Channel与Stream的对比
Stream | Channel | 为什么 | |
---|---|---|---|
是否支持异步 | 否 | 是 | |
是否同时支持输入和输出 | 否 | 是 | Stream的输入、输出分别需要InputStream、OutputStream |
是否必须结合Buffer使用 | 否 | 是 | 缓冲区是通道内部发送数据和接收数据的端点 |
性能 | 低 | 高 | 通道是访问IO服务的导管,通过通道,我们可以以最小的开销来访问操作系统的I/O服务 |
1.2:Channel的类型
文件类:
- FileChannel
可通过 FileInputStream/FileOutputStream 的getChannel方法获取通道。
网络类:
基于socket协议:
- SocketChannel
- ServerSocketChannel
可通过 Socket/SocketServer 的getChannel方法获取通道。
基于UDP协议:
- DatagramChannel
可通过 DatagramSocket 的getChannel方法获取通道。
1.3:操作系统IO演变史
早一代IO操作是由CPU负责IO接口:
新一代DMA授权处理IO接口:
通道(Channel)模式:
通道的产生是由于操作系统的升级而支持的。
2:Channel和操作系统的关系
在操作系统中对IO设备的控制方式一共有四种,按时间线依次是 轮询、中断、DMA、和通道 方式。
- 轮旋
轮询就是进行IO时操作系统一直问控制器数据准备好了没有。
- 中断
中断就是异步的方式进行了,CPU向设备控制器发送一条IO指令后接着返回继续做原来的工作,而当设备控制器从设备中取出数据放到控制器的寄存器中后便向CPU发送中断信号,CPU在检查完数据后便向控制器发送取走数据的信号,将数据写入内存,但仍是以字节为单位的。
- DMA
DMA则是CPU和设备控制器之间的引入的一层加快速度的手段,由DMA代替CPU进行数据传送,CPU将指令发送给DMA,DMA向控制器发送请求,设备控制器将数据从缓冲区将数据直接写入内存。完成后设备控制器发送一个信号给DMA,DMA重复检查数据是否传送完成,确认完成后中断让CPU知道。
DMA比起中断方式已经显著减少了CPU的干预,但是CPU每发出一条IO指令,只能去读写一个连续的数据块,当要读多个数据块并存放到不同的内存区域中去,CPU需要发送多条IO指令及进行多次中断。
- 通道
IO通道方式是DMA方式的发展,把对一个数据块的干预减少为对一组数据块的干预。
IO通道有三种:
- 字节多路通道(Byte Multiplexor Channel)
- 选择通道(Block Selector Channel)
- 数组多路通道(Block Multiplexor Channel)
根据通道的工作方式分类,通道可以分为字节多路通道、选择通道、数组多路通道。
字节多路通道是一种简单的共享通道,主要用于连接大量的低速设备。
由于外围设备的工作速度较慢,通道在传送两个字节之间有很多空闲的时间,利用这段空闲时间字节多路通道可以为其他外围设备服务。因此字节多路通道采用分时工作方式,依赖它与CPU之间的高速总线分时为多台外围设备服务。
数据选择通道用于连接高速的外围设备。
高速外围设备需要很高的数据传输率,因此不能采用字节多路通道那样的控制方式。选择通道在物理上可以连接多台外围设备,但多台设备不能同事工作。也就是在同一段时间内,选择通道只能为一台外围设备服务,在不同的时间内可以选择不同的外围设备。一旦选中某一设备,通道就进入忙状态,知道该设备数据传输工作结束,才能为其他设备服务。
数组多路通道是字节多路通道和选择通道的结合。
其基本思想是:当某设备进行数据传输时,通道只为该设备服务;当设备在进行寻址等控制性操作时,通道暂时断开与设备的连接,挂起该设备的通道程序,去为其他设备服务,即执行其他设备的通道程序。有数数组多路通道既保持了选择通道的告诉传输数据的有点,又充分利用了控制性操作偶读时间间隔为其他设备服务,使得通道效率充分得到发挥,因此数据多路通道在实际计算机系统中应用最多,适合于高速设备的数据传输。(以上引用内容来源于百度教育)
至于JAVA的Channel和操作系统的的通道是如何选择通道类型、如何交互的就没法深入了,暂且理解JAVA的Channel是对操作系统的通道的一种抽象实现吧。
3:Channel文件通道
上一篇已经介绍过Channel的文件内存映射(map),就不做介绍了。
所谓的分散读取、聚集写入就是用多个buffer来接收数据、传输数据。
分散读取、聚集写入代码示例:
@Test
public void gatherWrite() {
FileInputStream inputStream = null;
FileOutputStream outputStream = null;
FileChannel inChannel = null;
FileChannel outChannel = null;
try {
File file = new File("src/test/java/com/loper/mine/SQLParserTest.java");
inputStream = new FileInputStream(file);
inChannel = inputStream.getChannel();
ByteBuffer buffer1 = ByteBuffer.allocate(8);
ByteBuffer buffer2 = ByteBuffer.allocate(15);
ByteBuffer[] buffers = new ByteBuffer[]{buffer1, buffer2};
// 分散读取
inChannel.read(buffers);
for (ByteBuffer buffer : buffers) {
buffer.flip();
System.out.println(buffer.mark());
}
File outFile = new File("src/test/java/com/loper/mine/1.txt");
outputStream = new FileOutputStream(outFile);
outChannel = outputStream.getChannel();
// 聚集写入
outChannel.write(buffers);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (inputStream != null)
inputStream.close();
if (outputStream != null)
outputStream.close();
if (inChannel != null)
inChannel.close();
if (outChannel != null)
outChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
4:Channel网络通道
4.1:socket协议
这部分代码比较复杂,可以翻看我的github代码,这里就不坐介绍了。
地址:https://github.com/zgq7/devloper-mine/tree/master/src/main/java/com/loper/mine/core/socket/nio
4.2:UDP协议
UDP发送数据:
@Test
public void send() {
DatagramChannel channel = null;
try {
channel = DatagramChannel.open();
// 设置为非阻塞
channel.configureBlocking(false);
ByteBuffer buffer = ByteBuffer.allocate(1024);
Scanner scanner = new Scanner(System.in);
while (true) {
String nextLine = scanner.nextLine();
buffer.put(nextLine.getBytes());
buffer.flip();
channel.send(buffer, new InetSocketAddress("127.0.0.1", 8056));
buffer.clear();
if ("over".equals(nextLine))
break;
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (channel != null) {
try {
channel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
UDP接收数据:
@Test
public void receive() {
DatagramChannel channel = null;
try {
channel = DatagramChannel.open();
// 设置为非阻塞
channel.configureBlocking(false);
channel.bind(new InetSocketAddress(8056));
Selector selector = Selector.open();
channel.register(selector, SelectionKey.OP_READ);
while (true) {
int select = selector.select();
boolean exit = false;
Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
while (iterator.hasNext()) {
SelectionKey selectionKey = iterator.next();
if (selectionKey.isReadable()) {
ByteBuffer buffer = ByteBuffer.allocate(1024);
channel.receive(buffer);
buffer.flip();
byte[] data = new byte[buffer.limit()];
buffer.get(data);
String str = new String(data);
System.out.println("收到:" + str);
if ("over".equals(str))
exit = true;
}
iterator.remove();
}
if (exit)
break;
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (channel != null) {
try {
channel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
接收端接收数据并退出:
以上即为本文理论知识+代码实战全部内容。如有错误欢迎指正。
本文参考文章:
Java-NIO之Channel(通道)的更多相关文章
- Java NIO中的通道Channel(二)分散/聚集 Scatter/Gather
什么是Scatter/Gather scatter/gather指的在多个缓冲区上实现一个简单的I/O操作,比如从通道中读取数据到多个缓冲区,或从多个缓冲区中写入数据到通道: scatter(分散): ...
- Java NIO中的通道Channel(一)通道基础
什么是通道Channel 这个说实话挺难定义的,有点抽象,不过我们可以根据它的用途来理解: 通道主要用于传输数据,从缓冲区的一侧传到另一侧的实体(如文件.套接字...),反之亦然: 通道是访问IO服务 ...
- Java NIO 之 Channel(通道)
历史回顾: Java NIO 概览 Java NIO 之 Buffer(缓冲区) 其他高赞文章: 面试中关于Redis的问题看这篇就够了 一文轻松搞懂redis集群原理及搭建与使用 一 Channel ...
- JAVA NIO之文件通道
1.简介 通道是 Java NIO 的核心内容之一,在使用上,通道需和缓存类(ByteBuffer)配合完成读写等操作.与传统的流式 IO 中数据单向流动不同,通道中的数据可以双向流动.通道既可以读, ...
- 【Java nio】Channel
package com.slp.nio; import org.junit.Test; import java.io.*; import java.nio.ByteBuffer; import jav ...
- java nio之channel
一.通道(Channel):由 java.nio.channels 包定义的.Channel 表示 IO 源与目标打开的连接.Channel 类似于传统的“流”.只不过 Channel本身不能直接访问 ...
- JAVA NIO 之Channel
缓冲区本质上是一块可以写入数据,然后可以从中读取数据的内存.Channel 通道就是将数据传输给 ByteBuffer 对象或者从 ByteBuffer 对象获取数据进行传输. Channel 用于在 ...
- java输入输出 -- java NIO之文件通道
一.简介 通道是 Java NIO 的核心内容之一,在使用上,通道需和缓存类(ByteBuffer)配合完成读写等操作.与传统的流式 IO 中数据单向流动不同,通道中的数据可以双向流动.通道既可以读, ...
- Java NIO教程 Channel
Channel是一个连接到数据源的通道.程序不能直接用Channel中的数据,必须让Channel与BtyeBuffer交互数据,才能使用Buffer中的数据. 我们用FileChannel作为引子, ...
- 《JAVA NIO》Channel
3.通道 Channle主要分为两类:File操作对应的FIleChannel和Stream操作对应的socket的3个channe. 1.这3个channel都是抽象类.其具体实现在SPI里面. 2 ...
随机推荐
- 单链表上的一系列操作(基于c语言)
单链表的实现分为两种单链表(其实差别并不是很大):带头结点和不带头结点,分别对应下面图中的上下两种. 链表的每一个结点是由两个域组成:数据域和指针域,分别存放所含数据和下一个结点的地址(这都是很明白的 ...
- m3u8文件合并处理
m3u8文件合并处理 简介 M3U8 是 Unicode 版本的 M3U,用 UTF-8 编码."M3U" 和 "M3U8" 文件都是苹果公司使用的 HTTP ...
- Redis 使用规范
Redis 使用规范围绕如下几个纬度展开: 键值对使用规范: 命令使用规范: 数据保存规范: 运维规范. 键值对使用规范 有两点需要注意: 好的 key 命名,才能提供可读性强.可维护性高的 key, ...
- Sobel算子 Scharr算子 Laplacian算子
图像梯度处理 Sobel算子 水平方向: 对于线条A和线条B,右侧像素值与左侧像素值的差值不为零,因此是边界 上下像素值差值为0,左右素值的差值不为零,分布为正负, 离的近的为2,离的远的为1 P5= ...
- Java基础——自动装箱与拆箱
装箱:把基本数据类型转换为对应的包装类类型 //装箱Integer i=Integer.ValuesOf(100);//自动装箱integer i1=100;//能够直接赋值成功的称为自动装箱,也调用 ...
- 同一局域网ping ip 失败(可能是你的路由器坑了你)
事件起源:手机需要通过fiddler代理抓包 一顿操作猛如虎,手机输入ip+端口,芭比q了,连接不上.. 解决思路: 一.保证双方处于同一局域网内 二.查看电脑配置,找到 防火墙,关闭防火墙,再试 三 ...
- winform 代码生成textbox ,checkbox
参考地址:https://jingyan.baidu.com/article/380abd0a6b80701d90192cde.html 首先搭建好Winform项目框架后,创建窗体页面后自行布局 这 ...
- git 的使用(新手)
git的使用心得 windows版本下载git地址 git config --global user.name 用户名 在使用git前要注册用户名(个人称谓) git config --global ...
- springboot-访问数据库
在springboot中,默认的JPA实现是Hibernate,JPA是Java Persistence API的简称,中文名Java持久层API <!--数据库--> <depen ...
- java中的VO、PO、BO、DAO、POJO
针对java工程里的各种带O的对象,进行分析,了解各自的作用. PO: persistent object,持久对象.与数据库里表字段一一对应.PO是一些属性,以及set和get方法组成.一般情况下 ...