(三:NIO系列) Java NIO Channel
出处: Java NIO Channel
1.1. Java NIO Channel的特点
和老的OIO相比,通道和NIO流(非阻塞IO)主要有以下几点区别:
(1)OIO流一般来说是单向的(只能读或者写),通道可以读也可以写。
(2)OIO流值读写阻塞的,而通道可以异步读写。
(3)通道总是基于缓冲区Buffer来读写。
1.2. Channel类型
下面列出Java NIO中最重要的集中Channel的实现:
(1)FileChannel
(2)DatagramChannel
(3)SocketChannel
(4)ServerSocketChannel
四种通道的说明如下:
FileChannel 用于文件的数据读写。
DatagramChannel 用于UDP的数据读写。
SocketChannel 用于TCP的数据读写。
ServerSocketChannel 允许我们监听TCP链接请求,每个请求会创建会一个SocketChannel。
这个四种通道,涵盖了 UDP 和 TCP网络 IO以及文件 IO的操作。下面从通道的新建、读取、写入、关闭等四个操作,四种通道进行简单的介绍。
1.3. FileChannel
FileChannel 是操作文件的Channel,我们可以通过 FileChannel 从一个文件中读取数据,也可以将数据写入到文件中。
注意,FileChannel 不能设置为非阻塞模式。
操作一:打开 FileChannel通道
RandomAccessFile aFile = new RandomAccessFile("test.txt","rw");
FileChannel inChannel = aFile.getChannel();
操作二:读取数据
ByteBuffer buf = ByteBuffer.allocate(48);
int bytesRead = inChannel.read(buf);
操作三:写入数据
String newData = "New String to write to file..." + System.currentTimeMillis();
ByteBuffer buf = ByteBuffer.allocate(48);
buf.clear();
buf.put(newData.getBytes());
buf.flip();
while(buf.hasRemaining())
{
channel.write(buf);
}
操作四:关闭
channel.close();
当我们对 FileChannel 的操作完成后,必须将其关闭。
操作五:强制刷新磁盘
channel.force(true);
FileChannel的force()方法将所有未写入的数据从通道刷新到磁盘中。在你调用该force()方法之前,出于性能原因,操作系统可能会将数据缓存在内存中,因此您不能保证写入通道的数据实际上写入磁盘。
1.4. SocketChannel
有两种Socket通道,一个是客户端的SocketChannel,一个是负责服务器端的Socket通道ServerSocketChannel。SocketChannel与OIO中的Socket类对应,ServerSocketChannel对应于OIO中的ServerSocket类相NIO。
两种Socket通道新增的通道都支持阻塞和非阻塞两种模式。在阻塞模式下的通道的创建、关闭、读写操作如下:
操作一:创建
SocketChannel socketChannel = SocketChannel.open();
socketChannel.connect(new InetSocketAddress("127.0.0.1",80));
这个是客户端的创建。当一个服务器端的ServerSocketChannel 接受到连接请求时,也会返回一个 SocketChannel 对象。
操作二:读取
ByteBuffer buf = ByteBuffer.allocate(48);
int bytesRead = socketChannel.read(buf);
如果 read()返回 -1,那么表示连接中断了.
操作三:写入数据
String newData = "New String to write to file..." + System.currentTimeMillis();
ByteBuffer buf = ByteBuffer.allocate(48);
buf.clear();
buf.put(newData.getBytes());
buf.flip();
while(buf.hasRemaining()) {
channel.write(buf);
}
操作四:关闭
socketChannel.close();
在非阻塞模式,我们可以设置 SocketChannel 为异步模式,这样我们的 connect,read,write 都是异步的了.
操作一:连接
socketChannel.configureBlocking(false);
socketChannel.connect(new InetSocketAddress("127.0.0.1",80));
while(! socketChannel.finishConnect() ){
//wait,or do something else...
}
在异步模式中,或许连接还没有建立,socketChannel.connect 方法就返回了,因此我们不断的自旋,检查当前是否是连接到了主机。
操作二:非阻塞读写
在异步模式下,读写的方式是一样的.
在读取时,因为是异步的,因此我们必须检查 read 的返回值,来判断当前是否读取到了数据.
ServerSocketChannel
ServerSocketChannel 顾名思义,是用在服务器为端的,可以监听客户端的 TCP 连接,例如:
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.socket().bind(new InetSocketAddress(9999));
while(true){
SocketChannel socketChannel = serverSocketChannel.accept();
//do something with socketChannel...
}
操作四:关闭
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.close();
1.4.1. 监听连接
我们可以使用ServerSocketChannel.accept()方法来监听客户端的 TCP 连接请求,accept()方法会阻塞,直到有连接到来,当有连接时,这个方法会返回一个 SocketChannel 对象:
while(true){
SocketChannel socketChannel = serverSocketChannel.accept();
//do something with socketChannel...
}
1.4.2. 非阻塞模式
在非阻塞模式下,accept()是非阻塞的,因此如果此时没有连接到来,那么 accept()方法会返回null:
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.socket().bind(new InetSocketAddress(9999));
serverSocketChannel.configureBlocking(false);
while(true){
SocketChannel socketChannel = serverSocketChannel.accept();
if(socketChannel != null){
//do something with socketChannel...
}
}
1.5. DatagramChannel
DatagramChannel 是用来处理 UDP 连接的.
操作一:打开
DatagramChannel channel = DatagramChannel.open();
channel.socket().bind(new InetSocketAddress(9999));
操作二:读取数据
ByteBuffer buf = ByteBuffer.allocate(48);
buf.clear();
channel.receive(buf);
操作三:发送数据
String newData = "New String to write to file..." + System.currentTimeMillis();
ByteBuffer buf = ByteBuffer.allocate(48);
buf.clear();
buf.put(newData.getBytes());
buf.flip();
int bytesSent = channel.send(buf,new InetSocketAddress("example.com",80));
连接到指定地址
因为 UDP 是非连接的,因此这个的 connect 并不是向 TCP 一样真正意义上的连接,因此我们仅仅可以从指定的地址中读取或写入数据.
channel.connect(new InetSocketAddress("example.com",80));
(三:NIO系列) Java NIO Channel的更多相关文章
- 【Java nio】java nio笔记
缓冲区操作:缓冲区,以及缓冲区如何工作,是所有I/O的基础.所谓“输入/输出”讲的无非就是把数据移出货移进缓冲区.进程执行I/O操作,归纳起来也就是向操作系统发出请求,让它要么把缓冲区里的数据排干,要 ...
- Java-杂项-java.nio:java.nio
ylbtech-Java-杂项-java.nio:java.nio java.nio全称java non-blocking IO,是指jdk1.4 及以上版本里提供的新api(New IO) ,为所有 ...
- java的nio之:java的nio系列教程之channel的概念
一:java的nio的channel Java NIO的通道类似流,但又有些不同: ==>既可以从通道中读取数据,又可以写数据到通道.但流的读写通常是单向的. ==>通道可以异步地读写. ...
- 转:Java NIO系列教程(二) Channel
Java NIO的通道类似流,但又有些不同: 既可以从通道中读取数据,又可以写数据到通道.但流的读写通常是单向的. 通道可以异步地读写. 通道中的数据总是要先读到一个Buffer,或者总是要从一个Bu ...
- java的nio之:java的nio系列教程之channel的数据交换
在Java NIO中,如果两个通道中有一个是FileChannel,那你可以直接将数据从一个channel(译者注:channel中文常译作通道)传输到另外一个channel. transferFro ...
- 【NIO】Java NIO之选择器
一.前言 前面已经学习了缓冲和通道,接着学习选择器. 二.选择器 2.1 选择器基础 选择器管理一个被注册的通道集合的信息和它们的就绪状态,通道和选择器一起被注册,并且选择器可更新通道的就绪状态,也可 ...
- 【NIO】Java NIO之通道
一.前言 前面学习了缓冲区的相关知识点,接下来学习通道. 二.通道 2.1 层次结构图 对于通道的类层次结构如下图所示. 其中,Channel是所有类的父类,其定义了通道的基本操作.从 Channel ...
- 我的Java开发学习之旅------>Java NIO 报java.nio.charset.MalformedInputException: Input length = 1异常
今天在使用Java NIO的Channel和Buffer进行文件操作时候,报了java.nio.charset.MalformedInputException: Input length = 1异常, ...
- 【JAVA NIO】java NIO
本文是博主深入学习Netty前的一些铺垫,之前只是使用Netty,用的很粗暴,导包,上网找个DEMO就直接用,对Netty中的组件了解并不深入. 于是再此总结下基础,并对一些核心组件作如下记录: 1. ...
- 【NIO】Java NIO之缓冲
一.前言 在笔者打算学习Netty框架时,发现很有必要先学习NIO,因此便有了本博文,首先介绍的是NIO中的缓冲. 二.缓冲 2.1 层次结构图 除了布尔类型外,其他基本类型都有相对应的缓冲区类,其继 ...
随机推荐
- 【Luogu4221】[WC2018] 州区划分
题目链接 题目描述 略 Sol 一个州合法就是州内点形成的子图中 不存在欧拉回路(一个点也算欧拉回路). 这个东西显然就状压 dp 一下: 设 \(f[S]\) 表示当前考虑了 \(S\) 这个集合内 ...
- 《SaltStack技术入门与实践》—— Renderer组件
Renderer组件 本章节参考<SaltStack技术入门与实践>,感谢该书作者: 刘继伟.沈灿.赵舜东 前面我们已经提过使用Python语言编写state.sls文件.在SaltSta ...
- NOIP模拟赛(by hzwer) T2 小奇的序列
[题目背景] 小奇总是在数学课上思考奇怪的问题. [问题描述] 给定一个长度为 n 的数列,以及 m 次询问,每次给出三个数 l,r 和 P, 询问 (a[l'] + a[l'+1] + ... + ...
- 词根——rect
词根rect:直 线索链 来源于简单词right righta.正确的,直的,右的 (正和直是不分的)n. 右,权利ad.正确地,在右边 rectifyv. 纠正,整顿把它直起来 rect+ify=直 ...
- linux运维、架构之路-Docker快速入门
一.Docker介绍 Docker是Docker.lnc公司开源的一个基于LXC技术之上构建的Container容器引擎,源代码托管在Github上,基于Go语言并遵从Apache2.0 ...
- SQL Server死锁问题:事务(进程 ID x)与另一个进程被死锁在 锁 | 通信缓冲区资源上并且已被选作死锁牺牲品。请重新运行该事务。
### The error occurred while setting parameters### SQL: update ERP_SCjh_zzc_pl set IF_TONGBU=1 where ...
- POJ 1434 Fill the Cisterns! (模拟 or 二分)
Fill the Cisterns! 题目链接: http://acm.hust.edu.cn/vjudge/contest/129783#problem/F Description During t ...
- org.xml.sax.SAXParseException: 元素类型 "input" 必须由匹配的结束标记 "</input>" 终止。
错误记录 Spring Boot推荐使用thymeleaf作为视图,按照SpringBoot实战一书的案例写Demo. 发生错误: org.xml.sax.SAXParseException: 元素类 ...
- Catalan numbers
w https://en.wikipedia.org/wiki/Catalan_number 路径规划
- centOS 7 安装nginx服务
一.安装相关依赖 yum install gcc-c++ yum install -y pcre pcre-devel yum install -y zlib zlib-devel yum insta ...