服务端代码
package com.nio.test;
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;
import java.util.Set;
public class NioServerApplication {
public static void main(String[] args) throws IOException {
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
Selector selector = Selector.open();
//绑定端口
serverSocketChannel.socket().bind(new InetSocketAddress(8080));
//设置为非阻塞
serverSocketChannel.configureBlocking(false);
//注册serverSocketChannel到selector,并关注OP_ACCEPT
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("服务端启动成功!");
while (true) {
//没有事件发生
if (selector.select(1000) == 0) {
continue;
}
//有事件发生,找到发生事件的Channel对应的SelectionKey合集
Set<SelectionKey> selectorKeys = selector.selectedKeys();
Iterator<SelectionKey> iterator = selectorKeys.iterator();
while (iterator.hasNext()) {
SelectionKey selectionKey = iterator.next();
// 发生 OP_ACCEPT 事件,处理连接请求
if (selectionKey.isAcceptable()) {
System.out.println("收到连接请求");
SocketChannel socketChannel = serverSocketChannel.accept();
socketChannel.configureBlocking(false);
// 将 socketChannel 也注册到 selector,关注 OP_READ事件,并给 socketChannel 关联 Buffer
socketChannel.register(selector, SelectionKey.OP_READ, new ReadWriteBuffer());
}
// 发生 OP_READ 事件,读客户端数据
if (selectionKey.isReadable()) {
System.out.println("读取就绪");
SocketChannel channel = (SocketChannel) selectionKey.channel();
//取出建立连接时添加的缓存
ReadWriteBuffer readWriteBuffer = (ReadWriteBuffer) selectionKey.attachment();
//读取数据
ByteBuffer readBuffer = readWriteBuffer.readBuffer;
int read;
StringBuilder stringBuilder = new StringBuilder();
while ((read = channel.read(readBuffer)) > 0) {
readBuffer.flip();
byte[] readByte = new byte[read];
readBuffer.get(readByte);
stringBuilder.append(new String(readByte));
readBuffer.clear();
}
System.out.println("msg form client:" + stringBuilder);
// 添加写事件
selectionKey.interestOps(selectionKey.interestOps() | SelectionKey.OP_WRITE);
// 回复客户端
String result = "服务端收到消息了!";
readWriteBuffer.writeBuffer.put(result.getBytes());
//读取不到数据就把channel关闭
if(read == -1) {
channel.close();
}
}
if (selectionKey.isWritable() && selectionKey.isValid()) {
System.out.println("写入就绪");
SocketChannel channel = (SocketChannel) selectionKey.channel();
//取出buffer进行读取
ReadWriteBuffer readWriteBuffer = (ReadWriteBuffer) selectionKey.attachment();
readWriteBuffer.writeBuffer.flip();
if(readWriteBuffer.writeBuffer.hasRemaining()) {
channel.write(readWriteBuffer.writeBuffer);
} else {
// 注销写事件
selectionKey.interestOps(selectionKey.interestOps() & ~SelectionKey.OP_WRITE);
}
// 将buffer中没有用到的数据进行迁移
readWriteBuffer.writeBuffer.compact();
}
// 手动从集合中移除当前的 selectionKey,防止重复处理事件
iterator.remove();
}
}
}
static class ReadWriteBuffer {
//处理读操作
ByteBuffer readBuffer = ByteBuffer.allocate(1024);
//处理写操作
ByteBuffer writeBuffer = ByteBuffer.allocate(1024);
}
}
客户端代码
package com.nio.test;
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;
import java.util.Scanner;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class NioClientApplication {
public static void main(String[] args) throws IOException {
//单线程池
ExecutorService single = Executors.newSingleThreadExecutor();
ByteBuffer readBuffer = ByteBuffer.allocate(1024);
ByteBuffer writeBuffer = ByteBuffer.allocate(1024);
Selector selector = Selector.open();
SocketChannel socketChannel = SocketChannel.open();
Scanner scanner = new Scanner(System.in);
socketChannel.configureBlocking(false);
//与服务端建立连接
socketChannel.connect(new InetSocketAddress("localhost", 8080));
socketChannel.register(selector, SelectionKey.OP_CONNECT);
while (true) {
if (selector.select(1000) == 0) {
continue;
}
Set<SelectionKey> selectionKeys = selector.selectedKeys();
Iterator<SelectionKey> iterator = selectionKeys.iterator();
while (iterator.hasNext()) {
SelectionKey selectionKey = iterator.next();
//处理连接事件
if (selectionKey.isConnectable()) {
if (socketChannel.finishConnect()) {
socketChannel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);
}
}
//处理读事件
if (selectionKey.isReadable()) {
readBuffer.clear();
int read = socketChannel.read(readBuffer);
byte[] readByte = new byte[read];
readBuffer.flip();
readBuffer.get(readByte);
System.out.println("读取到数据:" + new String(readByte));
//重新注册写事件
selectionKey.interestOps(selectionKey.interestOps() | SelectionKey.OP_WRITE);
}
//处理写事件
if (selectionKey.isWritable()) {
//使用线程写数据到服务端
threadWrite(single, writeBuffer, socketChannel, scanner);
//取消注册写事件(不取消会造成上一次数据可能还没发送,下次进来还会继续执行
selectionKey.interestOps(selectionKey.interestOps() & ~SelectionKey.OP_WRITE);
}
}
iterator.remove();
}
}
static void threadWrite(ExecutorService single, ByteBuffer writeBuffer, SocketChannel socketChannel, Scanner scanner) {
single.execute(() -> {
try {
TimeUnit.SECONDS.sleep(1);
System.out.println(Thread.currentThread().getName() + "请输入:");
String line = scanner.nextLine();
writeBuffer.put(line.getBytes());
writeBuffer.flip();
//写入数据
while (writeBuffer.hasRemaining()) {
socketChannel.write(writeBuffer);
}
writeBuffer.compact();
} catch (Exception e) {
e.printStackTrace();
}
});
}
}
操作步骤:先启动服务端NioServerApplication,在启动客户端NioClientApplication。
就是一个入门的简单例子。