NIO-Channel详解
1.Channel概述
Channel即通道,表示打开IO设备的连接,⽐如打开到⽂件、Socket套接字的连接。在使⽤NIO时,必须要获取⽤于连接IO设备的通道以及⽤于容纳数据的缓冲区。通过操作缓冲区,实现对数据的处理。也就是说数据是保存在buffer缓冲区中的,需要通过Channel来操作缓冲区中的数据。
Channel相⽐IO流中的Stream更加⾼效,可以异步双向传输。
Channel的主要实现类有以下⼏个:
-
FileChannel:读写⽂件的通道
-
SocketChannel:读写TCP⽹络数据的通道
-
ServerSocketChannel:像web服务器⼀样,监听新进来的TCP连接,为连接创建SocketChannel
-
DatagramChannel:读写UDP⽹络数据的通道
2.FileChannel详解
FileChannel介绍
⽤于读取、写⼊、映射和操作⽂件的通道。⽂件通道是连接到⽂件的可搜索字节通道。它在其⽂件中有⼀个当前位置,可以查询和修改。⽂件本身包含可变⻓度的字节序列,可以读取和写⼊,并且可以查询其当前⼤⼩。当写⼊的字节超过其当前⼤⼩时,⽂件的⼤⼩增加;⽂件被截断时,其⼤⼩会减⼩。⽂件还可能具有⼀些相关联的元数据,如访问权限、内容类型和上次修改时间;此类不定义元数据访问的⽅法。
除了熟悉的字节通道读、写和关闭操作外,此类还定义了以下⽂件特定操作:
-
字节可以以不影响通道当前位置的⽅式在⽂件中的绝对位置读取或写⼊。
-
⽂件的区域可以直接映射到存储器中;对于⼤型⽂件,这⽐调⽤通常的读或写⽅法更有效。
-
对⽂件进⾏的更新可能会被强制输出到底层存储设备,以确保在系统崩溃时数据不会丢失。
-
字节可以从⼀个⽂件传输到另⼀个通道,反之亦然,许多操作系统都可以将其优化为直接从⽂件系统缓存进⾏⾮常快速的传输。
-
⽂件的⼀个区域可以被锁定以防⽌其他程序访问。
多个并发线程使⽤⽂件通道是安全的。根据通道接⼝的指定,可以随时调⽤close⽅法。在任何给定时间,只有⼀个涉及通道位置或可以改变其⽂件⼤⼩的操作正在进⾏;在第⼀个操作仍在进⾏时尝试发起第⼆个这样的操作将被阻⽌,直到第⼀个操作完成。其他⾏动,特别是采取明确⽴场的⾏动,可以同时进⾏;它们是否真的这样做取决于底层实现,因此没有具体说明。
FileChannel实例
-
FileChannel读文件
-
FileChannel写数据
-
通道之间传输数据一
-
通道之间传输数据二
3.Socket通道介绍
⾯向流的连接通道。Socket通道⽤于管理socket和socket之间的通道。Socket通道具有以下特点:
-
可以实现⾮阻塞,⼀个线程可以同时管理多个Socket连接,提升系统的吞吐量。
-
Socket通道的实现类(DatagramChannel、SocketChannel和ServerSocketChannel)在被实例化时会创建⼀个对等的Socket对象,也可以从Socket对象中通过getChannel()⽅法获得对应的Channel。
4.ServerSocketChannel详解
ServerSocketChannel是⼀个基于通道的Socket监听器,能够实现⾮阻塞模式。
ServerSocketChannel的主要作⽤是⽤来监听端⼝的连接,来创建SocketChannel。也就是说,可以调⽤ServerSocketChannel的accept⽅法,来创建SocketChannel对象。
示例
5.SocketChannel详解
SocketChannel介绍
SocketChannel是连接到TCP⽹络套接字的通道,更多代表的是客户端的操作。
SocketChannel具有以下特点:
-
SocketChannel连接的是Socket套接字,也就是说通道的两边是Socket套接字
-
SocketChannel是⽤来处理⽹络IO的通道
-
SocketChannel是可选择的,可以被多路复⽤
-
SocketChannel基于TCP连接传输
SocketChannel使⽤细节
SocketChannel在使⽤上需要注意以下细节:
-
不能在已经存在的Socket上再创建SocketChannel
-
SocketChannel需要指明关联的服务器地址及端⼝后才能使⽤
-
未进⾏连接的SocketChannel进⾏IO操作时将抛出NotYetConnectedException异常
-
SocketChannel⽀持阻塞和⾮阻塞两种模式
-
SocketChannel⽀持异步关闭。
-
SocketChannel⽀持设定参数
参数名称 | Description |
---|---|
SO_SNDBUF | Socket发送缓冲区的大小 |
SO_RCVBUF | Socket接收缓冲区的大小 |
SO_KEEPALIVE | 保活连接 |
SO_REUSEADDR | 复用地址 |
SO_LINGER | 有数据传输时延缓关闭Channel |
TCP——NODELAY | 禁用Nagle算法 |
SocketChannel示例
-
创建SocketChannel,同时会去连接服务端
-
方式一
-
方式二
-
-
连接状态校验
-
socketChannel.isOpen(): 判断SocketChannel是否为open状态
-
socketChannel.isConnected(): 判断SocketChannel是否已连接
-
socketChannel.isConnectionPending(): 判断SocketChannel是否正在进⾏连接
-
socketChannel.finishConnect(): 完成连接,如果此通道已连接,则此⽅法将不会阻塞,并将⽴即返回true。如果此通道处于⾮阻塞模式,则如果连接过程尚未完成,则此⽅法将返回false。如果此通道处于阻塞模式,则此⽅法将阻塞,直到连接完成或失败,并且将始终返回true或抛出⼀个描述失败的检查异常。
-
-
阻塞与非阻塞
-
读写操作
6.DatagramChannel详解
DatagramChannel对象关联着⼀个DatagramSocket对象。
DatagramChannel基于UDP⽆连接协议,每个数据报都是⼀个⾃包含的实体,拥有它⾃⼰的⽬的地址及数据负载。DatagramChannel可以发送单独的数据报给不同的⽬的地,同样也可以接受来⾃于任意地址的数据报。
-
示例一
-
使用read和write来表示接收和发送
DatagramChannel并不会建立连接通道,这里的read和write方法是在缓冲区中进行读写,来表达发送和接收的动作。
7.分散和聚集
Java NIO的分散Scatter和聚集Gather允许⽤户通过channel⼀次读取到的数据存⼊到多个buffer中,或者⼀次将多个buffer中的数据写⼊到⼀个Channel中。分散和聚集的应⽤场景可以是将数据的多个部分存放在不同的buffer中来进⾏读写
-
分散Scatter
在一个channel中读取的数据存入到多个buffer中
-
聚集
一次将多个buffer中的数据写入到一个channel中