1. BIO、NIO、AIO的区别?
BIO的特点:面向流、阻塞IO
面向流的IO只能一个字节一个字节读取,通过输入流产生一个字节数据,输出流消费一个字节数据,字节处理速度缓慢。并且在调用read()和write()时线程阻塞,直到有数据被读取或全部数据被写入。阻塞期间不能进行任何其他操作。
NIO的特点:面向缓冲区、非阻塞IO、同步
缓冲区(Buffer): 除boolean外,其余每个基本类型都有其对应的XXBuffer用来存取数据。
通道(Channel): 使用write()和read()方法用来接收和发送缓冲区数据。
选择器(Selector): 通道注册在选择器中,用来管理通道,采用多路复用技术,轮询选择一个当前准备就绪的通道。
以块的形式读取数据,每次产生一个数据块或者消费一个数据块,数据处理速度快。当线程从通道中读取当前数据时,只会读到目前已经有的数据或者读不到数据,写入数据时不需要等到全部写入。期间线程可以完成其他操作,不会阻塞。
AIO的特点:异步、非阻塞
真正实现异步IO请求,将IO请求从应用程序转到操作系统,让操作系统执行IO请求。
2. NIO示例代码
package com.clxk1997;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
/**
* @Description 服务端
* @Author Clxk
* @Date 2019/4/9 14:46
* @Version 1.0
*/
public class NIOServer {
private Selector selector;
private ServerSocketChannel serverSocketChannel = null;
private int keys = 0;
public void start() throws IOException {
NIOServer ns = new NIOServer();
//初始化服务端连接
ns.initConnect();
//监听客户端的连接
ns.listen();
}
/**
* 监听客户端的连接
*/
private void listen() throws IOException {
while(true) {
//让通道管理器至少选择一个通道
keys = this.selector.select();
Iterator it = this.selector.selectedKeys().iterator();
if(keys > 0) {
while(it.hasNext()) {
SelectionKey key = (SelectionKey) it.next();
it.remove();
//客户端请求连接事件
if(key.isAcceptable()) {
serverSocketChannel = (ServerSocketChannel) key.channel();
//获得和客户端连接的通道
SocketChannel socketChannel = serverSocketChannel.accept();
socketChannel.configureBlocking(false);
socketChannel.write(ByteBuffer.wrap("Hello Client.".getBytes()));
socketChannel.register(this.selector,SelectionKey.OP_READ);
} else if(key.isReadable()) {
read(key);
}
}
} else {
System.out.println("Selector finished without any keys.");
}
}
}
private void read(SelectionKey key) throws IOException {
SocketChannel socketChannel = (SocketChannel) key.channel();
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
int len = socketChannel.read(byteBuffer);
String msg = "服务端收到的消息是: " + new String(byteBuffer.array(),0,len);
System.out.println(msg);
}
/**
* 初始化服务端的连接通道和管理器,已经注册事件
*/
private void initConnect() throws IOException {
this.selector = Selector.open();
serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.socket().bind(new InetSocketAddress("127.0.0.1",8888));
serverSocketChannel.configureBlocking(false);
SelectionKey key = serverSocketChannel.register(selector,SelectionKey.OP_ACCEPT);
System.out.println("服务端启动成功!");
}
public static void main(String[] args) throws IOException {
new NIOServer().start();
}
}
package com.clxk1997;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
/**
* @Description 客户端
* @Author Clxk
* @Date 2019/4/9 14:46
* @Version 1.0
*/
public class NIOClient {
private Selector selector;
private SocketChannel socketChannel = null;
private ByteBuffer outBuff = ByteBuffer.allocate(1024);
private ByteBuffer inBuff = ByteBuffer.allocate(1024);
private int keys = 0;
public void start() throws IOException {
initConnect();
listen();
}
public void listen() throws IOException {
while(true) {
keys = this.selector.select();
if(keys > 0) {
Iterator it = this.selector.selectedKeys().iterator();
while(it.hasNext()) {
SelectionKey key = (SelectionKey) it.next();
if(key.isConnectable()) {
SocketChannel sc = (SocketChannel) key.channel();
if(sc.isConnectionPending()) {
sc.finishConnect();
System.out.println("完成连接!");
}
sc.register(this.selector,SelectionKey.OP_WRITE);
} else if(key.isWritable()) {
SocketChannel sc = (SocketChannel) key.channel();
outBuff.clear();
System.out.println("客户端正在写数据...");
sc.write(outBuff.wrap("我是ClientA".getBytes()));
sc.register(this.selector,SelectionKey.OP_READ);
System.out.println("客户端写数据完成!");
} else if(key.isReadable()) {
SocketChannel sc = (SocketChannel) key.channel();
inBuff.clear();
System.out.println("客户端正在读数据...");
sc.read(inBuff);
System.out.println(new String(inBuff.array()));
System.out.println("客户端读数据完成!");
}
}
} else {
System.out.println("没有找到感兴趣的事件.");
}
}
}
/**
* 初始化客户端连接
* @throws IOException
*/
public void initConnect() throws IOException {
selector = Selector.open();
socketChannel = SocketChannel.open();
socketChannel.configureBlocking(false);
socketChannel.connect(new InetSocketAddress("127.0.0.1",8888));
socketChannel.register(this.selector, SelectionKey.OP_CONNECT);
System.out.println("客户端启动成功!");
}
public static void main(String args[]) throws IOException {
new NIOClient().start();
}
}
3. AIO示例代码
package com.aio;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.util.concurrent.ExecutionException;
/**
* @Description 服务端
* @Author Clxk
* @Date 2019/4/9 21:19
* @Version 1.0
*/
public class AIOServer {
private AsynchronousServerSocketChannel serverSocketChannel = null;
public AIOServer() throws IOException {
serverSocketChannel = AsynchronousServerSocketChannel.open().bind(new InetSocketAddress(8888));
serverSocketChannel.accept(null, new CompletionHandler<AsynchronousSocketChannel, Void>() {
@Override
public void completed(AsynchronousSocketChannel result, Void attachment) {
serverSocketChannel.accept(null,this);
try {
handle(result);
} catch (ExecutionException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public void failed(Throwable exc, Void attachment) {
System.out.println("服务端启动失败!");
}
});
}
public void handle(AsynchronousSocketChannel result) throws ExecutionException, InterruptedException {
ByteBuffer buffer = ByteBuffer.allocate(1024);
result.read(buffer).get();
buffer.flip();
System.out.println("服务端接收: " + buffer.get());
}
public static void main(String[] args) throws InterruptedException, IOException {
AIOServer aioServer = new AIOServer();
System.out.println("服务端开始监听...");
Thread.sleep(10000);
}
}
package com.aio;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
/**
* @Description 客户端
* @Author Clxk
* @Date 2019/4/9 21:26
* @Version 1.0
*/
public class AIOClient {
private AsynchronousSocketChannel socketChannel = null;
public AIOClient() throws IOException, ExecutionException, InterruptedException {
socketChannel = AsynchronousSocketChannel.open();
Future<?> future = socketChannel.connect(new InetSocketAddress("127.0.0.1",8888));
System.out.println(future.get());
}
public void write(byte b) {
ByteBuffer buffer = ByteBuffer.allocate(8);
buffer.put(b);
buffer.flip();
socketChannel.write(buffer);
}
public static void main(String[] args) throws InterruptedException, ExecutionException, IOException {
AIOClient aioClient = new AIOClient();
aioClient.write((byte) 20);
}
}