NIO学习之群聊系统
服务基础抽象类
package com.dawn.yi.netty.group;
import java.io.IOException;
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.Set;
public abstract class AbstractServer {
protected final Selector selector;
protected final String host;
protected final int port;
protected AbstractServer(String host, int port) throws IOException {
this.host = host;
this.port = port;
this.selector = Selector.open();
}
protected abstract AbstractServer initialize();
protected abstract void start();
protected void handleHappenedEvent() {
Set<SelectionKey> happenEventSelectionKeys = selector.selectedKeys();
Iterator<SelectionKey> iterator = happenEventSelectionKeys.iterator();
SelectionKey happenEventSelectionKey;
while (iterator.hasNext()) {
happenEventSelectionKey = iterator.next();
if (happenEventSelectionKey.isAcceptable()) {
accept();
}
if (happenEventSelectionKey.isWritable()) {
write(happenEventSelectionKey);
}
if (happenEventSelectionKey.isReadable()) {
read(happenEventSelectionKey);
}
iterator.remove();
}
}
protected abstract void accept();
protected abstract void read(SelectionKey selectionKey);
protected abstract void write(SelectionKey selectionKey);
protected SocketChannel getSocketChannel(SelectionKey selectionKey) {
return (SocketChannel) selectionKey.channel();
}
protected ByteBuffer getByteBuffer(int capacity) {
return ByteBuffer.allocate(capacity);
}
protected void leave(SelectionKey selectionKey, SocketChannel channel) throws IOException {
selectionKey.channel();
channel.close();
}
}
服务端
package com.dawn.yi.netty.group;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
public class GroupChatServer extends AbstractServer {
private final ServerSocketChannel server;
public GroupChatServer(ServerSocketChannel server) throws IOException {
super("127.0.0.1", 51225);
this.server = server;
}
public static void main(String[] args) throws IOException {
new GroupChatServer(ServerSocketChannel.open()).initialize().start();
}
@Override
protected AbstractServer initialize() {
try {
server.socket().bind(new InetSocketAddress(port));
server.configureBlocking(false);
server.register(selector, SelectionKey.OP_ACCEPT);
} catch (IOException e) {
e.printStackTrace();
}
return this;
}
@Override
public void start() {
System.out.println("服务器启动。。。");
for (; ; ) {
try {
if (selector.select(2000) == 0) {
System.out.println("服务器等待了2秒,没有客户端连接");
continue;
}
handleHappenedEvent();
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Override
protected void accept() {
try {
SocketChannel client = server.accept();
client.configureBlocking(false);
System.out.printf("客户端%s连接%n", client.getRemoteAddress());
client.register(selector, SelectionKey.OP_READ);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
protected void read(SelectionKey selectionKey) {
SocketChannel channel = getSocketChannel(selectionKey);
ByteBuffer buffer = getByteBuffer(2048);
try {
int count = channel.read(buffer);
if (count > 0) {
String message = new String(buffer.array());
System.out.printf("客户端%s发来的数据:%s%n", channel.getRemoteAddress(), message);
buffer.clear();
toForward(String.format("收到客户端%s的消息:%s", channel.getRemoteAddress(), message), selectionKey);
}
} catch (IOException e) {
try {
System.out.printf("客户端%s已离线。。。%n", channel.getRemoteAddress());
leave(selectionKey, channel);
} catch (IOException ioException) {
ioException.printStackTrace();
}
}
}
@Override
protected void write(SelectionKey selectionKey) {
}
private void toForward(String message, SelectionKey fromKey) {
selector.keys().stream()
.filter(key -> key.channel() instanceof SocketChannel && key != fromKey)
.forEach(key -> {
try {
getSocketChannel(key).write(ByteBuffer.wrap(message.getBytes()));
} catch (IOException e) {
e.printStackTrace();
}
});
}
}
客户端
package com.dawn.yi.netty.group;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;
import java.util.Scanner;
import java.util.concurrent.CompletableFuture;
public class GroupChatClient extends AbstractServer {
private final SocketChannel client;
protected GroupChatClient(SocketChannel client) throws IOException {
super("127.0.0.1", 51225);
this.client = client;
}
public static void main(String[] args) throws IOException {
new GroupChatClient(SocketChannel.open()).initialize().start();
}
@Override
protected AbstractServer initialize() {
try {
client.connect(new InetSocketAddress(host, port));
client.configureBlocking(false);
client.register(selector, SelectionKey.OP_READ);
if (!client.isConnected()) {
for (; ; ) {
if (!client.finishConnect()) {
System.out.println("客户端连接需要一段时间。。。");
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
return this;
}
@Override
protected void start() {
System.out.println("客户端启动。。。");
CompletableFuture.runAsync(() -> {
for (; ; ) {
try {
if (selector.select(2000) == 0) {
continue;
}
handleHappenedEvent();
} catch (IOException e) {
e.printStackTrace();
}
}
});
Scanner in = new Scanner(System.in);
while (in.hasNextLine()) {
try {
System.out.println("请输入: ");
client.write(ByteBuffer.wrap(in.nextLine().getBytes()));
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Override
protected void read(SelectionKey selectionKey) {
SocketChannel channel = getSocketChannel(selectionKey);
ByteBuffer buffer = getByteBuffer(2048);
try {
int count = channel.read(buffer);
if (count > 0) {
System.out.println(new String(buffer.array()));
}
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
protected void accept() {
}
@Override
protected void write(SelectionKey selectionKey) {
}
}