java提供了IO、NIO、AIO包,用于处理输入输出。
BIO:Block IO 同步阻塞式 IO,就是我们平常使用的传统 IO,它的特点是模式简单使用方便,并发处理能力低。
NIO:Non IO 同步非阻塞 IO,是传统 IO 的升级,客户端和服务器端通过 Channel(通道)通讯,实现了多路复用。
AIO:Asynchronous IO 是 NIO 的升级,也叫 NIO2,实现了异步非堵塞 IO ,异步 IO 的操作基于事件和回调机制
IO
IO就是我们常用的 java.io包,它基于流模型,提供了File 抽象、输入输出流等。因为是同步阻塞的,也有人称为BIO。好处就是可靠,返回后可以立刻知晓结果。
按数据分:字符流(InputStream、OutputStream)、字节流。
按操作分:输入流、输出流。

注:IO流的缓冲区是用来提高效率的。
NIO
NIO的三个主要组成部分:Channel(通道)、Buffer(缓冲区)、Selector(选择器)。它们关系可以简单下图说明:

Channel
可以通过它读取和写入数据,类似IO中的流,不过它可以用于读、写或者同时用于读写。一个Channel绑定一个Buffer。
FileChannel
DatagramChannel
SocketChannel
ServerSocketChannel
Buffer
NIO有如下 buffer:
ByteBuffer, CharBuffer, DoubleBuffer, FloatBuffer, IntBuffer, LongBuffer, ShortBuffer
这些Buffer类型代表了不同的数据类型。换句话说,就是可以通过char,short,int,long,float 或 double类型来操作缓冲区中的字节。
Selector
Selector 对象上可以注册很多个Channel,监听各个Channel上发生的事件,当事件发生时决定Channel读写。这样使用Selector就可以做到用一个线程来处理所有的channels,毕竟线程之间的切换的代价很高。
创建selector
Selector selector = Selector.open();
注册channel的事件
channel.configureBlocking(false);// 注意这里channel一定要设置成异步模式,不然报错
SelectionKey key = channel.register(selector,SelectionKey.OP_READ);
对应事件说明:
| 事件 | 功能 | 对应判断方法 |
| SelectionKey.OP_ACCEP | 服务器监听到了客户连接,服务器可以接收这个连接 | selectionKey.isAcceptable(); |
| SelectionKey.OP_CONNECT | 连接就绪事件,表示客户端与服务器的连接已经建立成功 | selectionKey.isConnectable(); |
| SelectionKey.OP_READ | 读就绪事件,表示通道中已经有了可读的数据,可以执行读操作 | selectionKey.isReadable(); |
| SelectionKey.OP_WRITE | 写就绪事件,表示已经可以向通道写数据 | selectionKey.isWritable(); |
如果要处理比较大的数据,从性能考虑建议用MappedByteBuffer。
看下示例:
public class MyMain {
public static void main(String[] args) throws IOException {
ByteBuffer sendbuffer = ByteBuffer.allocate(2048);
ByteBuffer receivebuffer = ByteBuffer.allocate(2048);
// 1 创建一个 Selector用于注册。当事件发生时,seletor 告诉你发生了什么
Selector selector = Selector.open();
ServerSocketChannel socketChannel = ServerSocketChannel.open();
socketChannel.configureBlocking(false);// 注意:一定要设置为 非阻塞的
ServerSocket socket = socketChannel.socket();
socket.bind(new InetSocketAddress("127.0.0.1", 2181));// 绑定到给定的端口
// 注册 accept 事件。值得一说的是因为Channel一定要是异步的,因此这里不能用 FileChannel
socketChannel.register(selector, SelectionKey.OP_ACCEPT);
while (true) {
// 这个方法会阻塞,直到至少有一个已注册的事件发生
selector.select();
// 返回此选择器的已选择键集。
Set<SelectionKey> selectionKeys = selector.selectedKeys();
Iterator<SelectionKey> iterator = selectionKeys.iterator();
while (iterator.hasNext()) {
SelectionKey selectionKey = iterator.next();
iterator.remove();
handleKey(selector, selectionKey, sendbuffer, receivebuffer);
}
}
}
// 处理请求
private static void handleKey(Selector selector, SelectionKey selectionKey, ByteBuffer sendBuffer, ByteBuffer receivebuffer) throws IOException {
// 接受请求
SocketChannel client = null;
int count = 0;
// 测试此键的通道是否已准备好接受新的套接字连接。
if (selectionKey.isAcceptable()) {
System.out.println("通道连接已可用");
// 返回为之创建此键的通道。
ServerSocketChannel server = (ServerSocketChannel) selectionKey.channel();
// 接受到此通道套接字的连接。
// 此方法返回的套接字通道(如果有)将处于阻塞模式。
client = server.accept();
// 配置为非阻塞
client.configureBlocking(false);
// 注册到selector,等待连接
client.register(selector, SelectionKey.OP_READ);
} else if (selectionKey.isReadable()) {
// 返回为之创建此键的通道。
client = (SocketChannel) selectionKey.channel();
//将缓冲区清空以备下次读取
receivebuffer.clear();
//读取服务器发送来的数据到缓冲区中
count = client.read(receivebuffer);
if (count > 0) {
System.out.println("从客户端获取的数据:" + new String(receivebuffer.array(), 0, count));
client.register(selector, SelectionKey.OP_WRITE);
}
} else if (selectionKey.isWritable()) {
System.out.println("可向客户端写数据");
//将缓冲区清空以备下次写入
sendBuffer.clear();
// 返回为之创建此键的通道。
client = (SocketChannel) selectionKey.channel();
sendBuffer.put("Hellow world".getBytes());
sendBuffer.flip();
//输出到通道
client.write(sendBuffer);
System.out.println("服务器端向客户端发送数据");
client.register(selector, SelectionKey.OP_READ);
}
}
}
启动后,输入 http://localhost:2181/ 后,就会在控制台发现有请求和可读时间发现
AIO
即java NIO2。NIO是同步非阻塞的,提升了性能。但还是异步的。NIO2是异步的,因此也称即AIO,即Asynchronous IO。异步 IO 操作是基于事件和回调机制的。
看下例子:
本文介绍了Java的IO、NIO和AIO。BIO是同步阻塞IO,适合简单场景;NIO提供Channel、Buffer和Selector,实现同步非阻塞,适合多路复用;AIO,又称NIO2,实现异步非阻塞,基于事件和回调,提升性能。
2499

被折叠的 条评论
为什么被折叠?



