public class NIOServer {
private ServerSocketChannel serverSocketChannel;
private Selector selector;
private static final int PORT = 1212;
public NIOServer() throws IOException {
// 先用open方法创建一个对象
serverSocketChannel = ServerSocketChannel.open();
// 绑定端口
serverSocketChannel.bind(new InetSocketAddress(“localhost”,PORT));
serverSocketChannel.configureBlocking(false);
// 创建一个Selector
selector = Selector.open();
// 把一个Channel注册到Selector
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
}
public void listen() throws IOException {
while (true) {
// 阻塞在 select
selector.select();
Set<SelectionKey> selectionKeys = selector.selectedKeys();
// 遍历selectKeys
Iterator<SelectionKey> iterator = selectionKeys.iterator();
while (iterator.hasNext()) {
SelectionKey key = iterator.next();
if (key.isAcceptable()) {
// accept事件
SocketChannel socketChannel = serverSocketChannel.accept();
System.out.println("accept new conn: " + socketChannel.getRemoteAddress());
socketChannel.configureBlocking(false);
socketChannel.register(selector, SelectionKey.OP_READ);
} else if (key.isReadable()) {
// 读取事件
readData(key);
}
iterator.remove();
}
}
}
private void readData(SelectionKey key) throws IOException {
SocketChannel socketChannel = (SocketChannel) key.channel();
// ByteBuffer buffer = ByteBuffer.allocateDirect(1024); 直接内存
ByteBuffer buffer = ByteBuffer.allocate(1024); // 内存
// 将数据读入到buffer中
int readBytes = 0; //
try {
readBytes = socketChannel.read(buffer);
if (readBytes > 0) {
buffer.flip();
// buffer.remaining()返回的是需要读多少字节
byte[] bytes = new byte[buffer.remaining()];
// 将数据写入到byte数组中
buffer.get(bytes);
String body = new String(bytes, StandardCharsets.UTF_8);
// 将消息分发给所有人
sendMessageToAll(socketChannel.getRemoteAddress() + "==>" + body, socketChannel);
if ("quit".equals(body)) {
//取消注册
key.cancel();
//关闭通道
socketChannel.close();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
private void sendMessageToAll(String body, SocketChannel self) throws IOException {
System.out.println(body);
for (SelectionKey key : selector.keys()) {
Channel targetChannel = key.channel();
// 不发送给自己
if (targetChannel instanceof SocketChannel && targetChannel != self) {
SocketChannel dest = (SocketChannel)targetChannel;
ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
buffer.put(body.getBytes(StandardCharsets.UTF_8));
buffer.flip();
dest.write(buffer);
}
}
}
public static void main(String[] args) throws IOException {
new NIOServer().listen();
}
}
客户端
public class NIOClient {
private SocketChannel socketChannel;
private volatile boolean isClosed = false;
public NIOClient() throws IOException {
socketChannel = SocketChannel.open();
socketChannel.connect(new InetSocketAddress("localhost",1212));
}
public void start() {
// 启动一个线程用来监听接收消息
new Thread(()->{
try {
// 创建一个Selector
Selector selector = Selector.open();
socketChannel.configureBlocking(false);
// 把一个Channel注册到Selector
socketChannel.register(selector, SelectionKey.OP_READ);
while (!isClosed) {
// 阻塞在 select
selector.select();
Set<SelectionKey> selectionKeys = selector.selectedKeys();
// 遍历selectKeys
Iterator<SelectionKey> iterator = selectionKeys.iterator();
while (iterator.hasNext()) {
SelectionKey key = iterator.next();
if (key.isReadable()) {
// 读取事件
SocketChannel sc = (SocketChannel) key.channel();
// ByteBuffer buffer = ByteBuffer.allocateDirect(1024); 直接内存
ByteBuffer buffer = ByteBuffer.allocate(1024); // 内存
// 将数据读入到buffer中
int readBytes = sc.read(buffer); //
if (readBytes > 0) {
buffer.flip();
// buffer.remaining()返回的是需要读多少字节
byte[] bytes = new byte[buffer.remaining()];
// 将数据写入到byte数组中
buffer.get(bytes);
String body = new String(bytes, StandardCharsets.UTF_8);
System.out.println(body);
}
}
iterator.remove();
}
}
socketChannel.close();
} catch (Exception e) {
e.printStackTrace();
}
}).start();
// 开启一个线程来发送消息
new Thread(()->{
// 主线程用来发送消息
Scanner sc = new Scanner(System.in);
while (true) {
String msg = sc.next();
ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
buffer.put(msg.getBytes(StandardCharsets.UTF_8));
buffer.flip();
try {
socketChannel.write(buffer);
} catch (IOException e) {
e.printStackTrace();
}
if ("quit".equals(msg)) {
this.isClosed = true;
break;
}
}
}).start();
}
public static void main(String[] args) throws IOException {
new NIOClient().start();
}
}
运行效果
[客户端一控制台]
我是lzc
/127.0.0.1:13003==>我是lisi
lisi你好啊
/127.0.0.1:13003==>你好你好
[客户端二控制台]
/127.0.0.1:12977==>我是lzc
我是lisi
/127.0.0.1:12977==>lisi你好啊
你好你好