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("连接断开");
}
}