NIO 三大组件
- Channel
- FileChannelel
- ServerSocketChannel
- SocketChannel
- DatagramChannel
- Buffer
- Selector
阻塞I/O与非阻塞I/O
- 非阻塞 I/O
- NIO 中的非阻塞I/O是基于 Reactor 模式的,在这里I/O的调用是不会阻塞的,相反是注册感兴趣的I/O事件。如可读数据到达,便会发生触发事件。NIO 中实现非阻塞I/O的核心对象是Selector。而 Selector就是注册各种事件的地方。非阻塞I/O指的是I/O事件本身不阻塞,但是获取事件的select()方法是需要阻塞等待的。而阻塞I/O则是阻塞在I/O操作上。NIO是阻塞在事件的获取上,没有事件就没有I/O,从这个层面看,I/O就是不会阻塞的了。
Channel
channel字面上便是“通道”的意思,它和IO中的Stream流是相似的,但是Stream是单向的,而Channel则是双向的(可以进行读/取操作)。NIO中 Channel 的实现有:FileChannel、DatagramChannel、SocketChannel、ServerSocketChannel。
NIO 中通过Channel 封装了对数据源的操作,这样便可以操作数据源,但又不必关心数据源的具体物理结构。channel与文件描述符或socket是相对应的。Channel用于在字节缓冲区和位于通道另一侧的实体之间有效的传输数据。
public interface Channel extends Closeable {
public boolean isOpen();
public void close() throws IOException;
}
与缓冲区不同,通道是一个接口定义,在不同的操作系统上有不同的实现,这样也 就会有一定的差异。因此在Channel接口中只是定义了它具有上面作用的方法。
同时Channel是一个对象,可以通过它读取和写入数据,而所有的数据都是通过Buffer来处理的。这样便不会将字节直接写入通道中,还有这里不会直接从通道中读取字节,而是将数据从通道读入缓冲区,然后再从缓冲区中读取。
Java NIO的通道类似流,但又有所不同:
- 既可以从通道中读取数据,也可以写数据到通道中,但是流到操作是单向的
- 通道可以异步的读写
- 通道中的数据总要先读到一个buffer,或者总是要从一个buffer中写入
Java NIO 中最重要的 Channel 的实现:
- FileChannel 从文件中读写数据
- DatagramChannel 能通过 UDP 读写网络中的数据
- SocketChannel 能通过 TCP 读写网络中的数据
- ServerSocketChannel 可以监听新进来的 TCP 连接,像 Web 服务器那样。对
每一个新进来的连接都会创建一个 SocketChannel。
FileChannel
public abstract class FileChannel
extends AbstractInterruptibleChannel
implements SeekableByteChannel, GatheringByteChannel, ScatteringByteChannel
{
// 省略
}
从上面的代码和图片中可以看出,FileChannel类分别继承了 AbstractInterruptibleChannel 和 实现了SeekableByteChannel,、GatheringByteChannel、ScatteringByteChannel,这里可以看下FileChannel类结构图:
从类结构图中可以清晰的看出,FileChannel类具有read,write的作用,是因为它实现了WritableByteChannel和ReadableByteChannel(这也说明通道只能在字节缓冲区上操作)。FileChannel 继承的 AbstractInterruptibleChannel 所实现的 InterruptibleChannel 类是一个具有异步关闭和终端功能的通道,因此 FileChannel 类也是具备这个能力的。
SocketChannel
public abstract class SocketChannel
extends AbstractSelectableChannel
implements ByteChannel, ScatteringByteChannel, GatheringByteChannel, NetworkChannel
{
// 省略
}
从类结构图上可以看出 SocketChannel 继承自 AbstractSelectableChannel,而 AbstractSelectableChannel 有继承了SelectableChannel,AbstractSelectableChannel 类是基于 SelectableChannel 进行进一步的抽象,SelectableChannel是一个具有多路复用的Channel类。SelectableChannel 也是继承了 AbstractInterruptibleChannel 类,这说明它和 FileChannel 一样具有异步关闭和终端的功能。不过这里可以看出 SocketChannel 实现了NetworkChannel 接口,NetworkChannel 代码如下:
public interface NetworkChannel
extends Channel
{
// 绑定地址到 NetworkChannel
NetworkChannel bind(SocketAddress local) throws IOException;
// 获取本地地址
SocketAddress getLocalAddress() throws IOException;
// 设置 SocketOption 的值
<T> NetworkChannel setOption(SocketOption<T> name, T value) throws IOException;
// 返回一个 SocketOption
<T> T getOption(SocketOption<T> name) throws IOException;
// 返回次通道的一组 SocketOption
Set<SocketOption<?>> supportedOptions();
}
DatagramChannel
public abstract class DatagramChannel
extends AbstractSelectableChannel
implements ByteChannel, ScatteringByteChannel, GatheringByteChannel, MulticastChannel
{
// 省略
}
DatagramChannel 所实现的接口和SocketChannel是一样了(除了多了个 MulticastChannel),DatagramChannel 也和SocketChannel 一样继承了 AbstractSelectableChannel,那么这里就只关注MulticastChannel接口,代码如下:
public interface MulticastChannel
extends NetworkChannel
{
@Override void close() throws IOException;
MembershipKey join(InetAddress group, NetworkInterface interf)
throws IOException;
MembershipKey join(InetAddress group, NetworkInterface interf, InetAddress source)
throws IOException;
}
MulticastChannel是一个支持互联网协议组播的网络通道接口,它里面定义了关闭通道、join等方法。
ServerSocketChannel
public abstract class ServerSocketChannel
extends AbstractSelectableChannel
implements NetworkChannel
{
// 省略
}
ServerSocketChannel 负责监听传入的连接和创建新的 SocketChannel 对象,它本身从不传输数据。