1.nio 流的过程有几个,连接,可读,读 ,返回 ;连接了不一定可读,等待浪费时间,这些时间可以去读其他的连接,selector是管理,管理全部测一下可不可读,只对可读的连接进行读取。同时,nio有缓冲区,可以一大勺一大勺的吃饭,io是一粒米一粒米的
2.aio的话就是可以读了就回调方法,不是直接走方法,是异步的;
3.io之前就是一直等
public class SelectorServer { public static void main(String[] args) throws IOException { Selector selector = Selector.open(); ServerSocketChannel server = ServerSocketChannel.open(); server.socket().bind(new InetSocketAddress(8080)); // 将其注册到 Selector 中,监听 OP_ACCEPT 事件 server.configureBlocking(false); server.register(selector, SelectionKey.OP_ACCEPT); while (true) { // 需要不断地去调用 select() 方法获取最新的准备好的通道 int readyChannels = selector.select(); if (readyChannels == 0) { continue; } Set<SelectionKey> readyKeys = selector.selectedKeys(); // 遍历 Iterator<SelectionKey> iterator = readyKeys.iterator(); while (iterator.hasNext()) { SelectionKey key = iterator.next(); iterator.remove(); if (key.isAcceptable()) { // 有已经接受的新的到服务端的连接 SocketChannel socketChannel = server.accept(); // 有新的连接并不代表这个通道就有数据, // 这里将这个新的 SocketChannel 注册到 Selector,监听 OP_READ 事件,等待数据 socketChannel.configureBlocking(false); socketChannel.register(selector, SelectionKey.OP_READ); } else if (key.isReadable()) { // 有数据可读 // 上面一个 if 分支中注册了监听 OP_READ 事件的 SocketChannel SocketChannel socketChannel = (SocketChannel) key.channel(); ByteBuffer readBuffer = ByteBuffer.allocate(1024); int num = socketChannel.read(readBuffer); if (num > 0) { // 处理进来的数据... System.out.println("收到数据:" + new String(readBuffer.array()).trim()); socketChannel.register(selector, SelectionKey.OP_WRITE); } else if (num == -1) { // -1 代表连接已经关闭 socketChannel.close(); } } else if (key.isWritable()) { // 通道可写 // 给用户返回数据的通道可以进行写操作了 SocketChannel socketChannel = (SocketChannel) key.channel(); ByteBuffer buffer = ByteBuffer.wrap("返回给客户端的数据...".getBytes()); socketChannel.write(buffer); // 重新注册这个通道,监听 OP_READ 事件,客户端还可以继续发送内容过来 socketChannel.register(selector, SelectionKey.OP_READ); } } } } }
aio
package com.javadoop.aio; import java.io.IOException; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.nio.ByteBuffer; import java.nio.channels.AsynchronousServerSocketChannel; import java.nio.channels.AsynchronousSocketChannel; import java.nio.channels.CompletionHandler; public class Server { public static void main(String[] args) throws IOException { // 实例化,并监听端口 AsynchronousServerSocketChannel server = AsynchronousServerSocketChannel.open().bind(new InetSocketAddress(8080)); // 自己定义一个 Attachment 类,用于传递一些信息 Attachment att = new Attachment(); att.setServer(server); server.accept(att, new CompletionHandler<AsynchronousSocketChannel, Attachment>() { @Override public void completed(AsynchronousSocketChannel client, Attachment att) { try { SocketAddress clientAddr = client.getRemoteAddress(); System.out.println("收到新的连接:" + clientAddr); // 收到新的连接后,server 应该重新调用 accept 方法等待新的连接进来 att.getServer().accept(att, this); Attachment newAtt = new Attachment(); newAtt.setServer(server); newAtt.setClient(client); newAtt.setReadMode(true); newAtt.setBuffer(ByteBuffer.allocate(2048)); // 这里也可以继续使用匿名实现类,不过代码不好看,所以这里专门定义一个类 client.read(newAtt.getBuffer(), newAtt, new ChannelHandler()); } catch (IOException ex) { ex.printStackTrace(); } } @Override public void failed(Throwable t, Attachment att) { System.out.println("accept failed"); } }); // 为了防止 main 线程退出 try { Thread.currentThread().join(); } catch (InterruptedException e) { } } }
package com.javadoop.aio; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.CompletionHandler; import java.nio.charset.Charset; public class ChannelHandler implements CompletionHandler<Integer, Attachment> { @Override public void completed(Integer result, Attachment att) { if (att.isReadMode()) { // 读取来自客户端的数据 ByteBuffer buffer = att.getBuffer(); buffer.flip(); byte bytes[] = new byte[buffer.limit()]; buffer.get(bytes); String msg = new String(buffer.array()).toString().trim(); System.out.println("收到来自客户端的数据: " + msg); // 响应客户端请求,返回数据 buffer.clear(); buffer.put("Response from server!".getBytes(Charset.forName("UTF-8"))); att.setReadMode(false); buffer.flip(); // 写数据到客户端也是异步 att.getClient().write(buffer, att, this); } else { // 到这里,说明往客户端写数据也结束了,有以下两种选择: // 1. 继续等待客户端发送新的数据过来 // att.setReadMode(true); // att.getBuffer().clear(); // att.getClient().read(att.getBuffer(), att, this); // 2. 既然服务端已经返回数据给客户端,断开这次的连接 try { att.getClient().close(); } catch (IOException e) { } } } @Override public void failed(Throwable t, Attachment att) { System.out.println("连接断开"); } }