- IO模型:BIO传统阻塞IO、NIO同步非阻塞IO、AIO异步非阻塞IO。
- 同步与阻塞:同步指读写过程,同步读写必须得到对方响应才继续往下进行,异步读写无须得到对方响应即可往下进行;阻塞与否是指线程。
- NIO:同步非阻塞IO模型,它的读写是同步的,线程的处理是非阻塞的,但是,不代表它不能实现“异步非阻塞”的效果。由于它的线程是非阻塞的,就好比BIO中开辟多个线程实现异步读写一样,NIO同样可以实现异步读写。
- NIO服务端测试代码
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.nio.channels.spi.SelectorProvider;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
public class NIOServer {
private static List<byte[]> command = new ArrayList<byte[]>();
private static void handlerAccept(SelectionKey key, Selector selector) throws IOException {
ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
SocketChannel socketChannel = ssc.accept();
socketChannel.configureBlocking(false);
socketChannel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);
System.out.println("服务器 接受连接:" + socketChannel.getRemoteAddress());
}
private static void handlerRead(SelectionKey key) throws IOException {
SocketChannel socketChannel = (SocketChannel) key.channel();
ByteBuffer readBuff = ByteBuffer.allocate(1024);
readBuff.clear();
int readSize = socketChannel.read(readBuff);
int pos = readBuff.position();
readBuff.flip();
byte[] bs = Arrays.copyOf(readBuff.array(), pos);
if (readSize > 0) {
System.out.print("服务器 读取数据 " + System.currentTimeMillis() / 1000 + " <== ");
for (byte b : bs) {
String hex = Integer.toHexString(b & 0xFF);
System.out.print(hex.length() < 2 ? "0" + hex : hex);
}
System.out.println("");
} else if (readSize == 0) {
} else {
System.out.println("服务器 断开连接" + socketChannel.getRemoteAddress());
key.cancel();
}
}
private static void handlerWrite(SelectionKey key) throws IOException {
if (command.size() > 0) {
ByteBuffer writeBuff = ByteBuffer.wrap(command.get(0));
command.remove(0);
SocketChannel socketChannel = (SocketChannel) key.channel();
socketChannel.write(writeBuff);
System.out.println(
"服务器 发送数据 " + System.currentTimeMillis() / 1000 + " ==> " + HexUtil.bytes2Hex(writeBuff.array()));
}
}
private static void autoRunCommand() {
new Thread(new Runnable() {
public void run() {
while (true) {
command.add(new byte[] { 0x1a, 0x2b, 0x3c });
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
public static void main(String[] args) throws Exception {
autoRunCommand();
SelectorProvider selectorProvider = SelectorProvider.provider();
ServerSocketChannel serverSocketChannel = selectorProvider.openServerSocketChannel();
serverSocketChannel.configureBlocking(false);
serverSocketChannel.socket().bind(new InetSocketAddress(1024), 10);
Selector selector = selectorProvider.openSelector();
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("NIO服务器就绪,等待连接....");
while (true) {
if (selector.select(1000) == 0)
continue;
Iterator<SelectionKey> it = selector.selectedKeys().iterator();
while (it.hasNext()) {
SelectionKey key = it.next();
it.remove();
if (key.isValid() && key.isAcceptable())
handlerAccept(key, selector);
if (key.isValid() && key.isReadable())
handlerRead(key);
if (key.isValid() && key.isWritable())
handlerWrite(key);
}
}
}
}
- BIO客户端测试代码
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Arrays;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class BIOClient {
private Socket socket;
private InputStream input;
private OutputStream output;
private ExecutorService pool = Executors.newFixedThreadPool(2);
public static void main(String[] args) throws IOException {
new BIOClient("localhost", 1024).start();
}
private BIOClient(String address, int port) {
try {
socket = new Socket(address, port);
this.input = socket.getInputStream();
this.output = socket.getOutputStream();
} catch (IOException e) {
e.printStackTrace();
}
}
public void start() {
pool.submit(new Runnable() {
public void run() {
new Writer().run();
}
});
pool.submit(new Runnable() {
public void run() {
new Reader().run();
}
});
}
private class Reader extends Thread {
@Override
public void run() {
try {
byte[] bs = new byte[1024];
int readSize = 0;
while ((readSize = input.read(bs)) > 0) {
System.out.print("客户端 读取数据 <== ");
for (byte b : Arrays.copyOf(bs, readSize)) {
String hex = Integer.toHexString(b & 0xFF);
System.out.print(hex.length() < 2 ? "0" + hex : hex);
}
System.out.println("");
}
System.out.println("客户端 读线程关闭");
if (!socket.isClosed())
socket.close();
if (!pool.isShutdown())
pool.shutdown();
} catch (Exception e) {
e.printStackTrace();
}
}
}
private class Writer extends Thread {
@Override
public void run() {
while (true) {
try {
Thread.sleep(5000);
byte[] bs = new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 };
if (null != output) {
output.write(bs);
System.out.print("客户端 发送数据 ==> ");
for (byte b : bs) {
String hex = Integer.toHexString(b & 0xFF);
System.out.print(hex.length() < 2 ? "0" + hex : hex);
}
System.out.println("");
} else {
System.out.println("客户端 写线程关闭");
if (!socket.isClosed())
socket.close();
if (!pool.isShutdown())
pool.shutdown();
break;
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}