Java IO 模型
3.7 NIO 群聊
3.7.1 效果图
server
client
3.7.2 server coding
public class NioServer {
private static final String HOST = "127.0.0.1";
private static final int PORT = 9099;
private Selector selector;
private ServerSocketChannel serverSocketChannel;
public NioServer() {
try {
// 创建 selector
selector = Selector.open();
// 开启 serverSocketChannel
serverSocketChannel = ServerSocketChannel.open();
// 绑定端口
serverSocketChannel.socket().bind(new InetSocketAddress(HOST, 9099));
// 设置为非阻塞模式
serverSocketChannel.configureBlocking(false);
// 将 serverSocketChannel 注册到 selector
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
} catch (Exception e) {
System.out.println("server 端启动异常");
e.printStackTrace();
}
}
public void listen() {
try {
while (true) {
// 等待事件处理
if (selector.select() == 0) {
System.out.println("等待 client 连接....");
continue;
}
// 处理连接的 client
// 获取所有连接的 client 事件
Set<SelectionKey> selectionKeys = selector.selectedKeys();
Iterator<SelectionKey> iterator = selectionKeys.iterator();
// 遍历事件
while (iterator.hasNext()) {
SelectionKey key = iterator.next();
// 处理 accept 事件
if (key.isAcceptable()) handlerAccept(key);
// 处理 read 事件
if (key.isReadable()) handlerRead(key);
// 移除处理完的 channel
iterator.remove();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void handlerAccept(SelectionKey key) {
try {
System.out.println("server 端处理 accept 事件...");
SocketChannel channel = serverSocketChannel.accept();
channel.configureBlocking(false);
channel.register(selector, SelectionKey.OP_READ);
System.out.println(channel.getRemoteAddress() + " 机器已经上线");
} catch (IOException e) {
e.printStackTrace();
}
}
private void handlerRead(SelectionKey key) {
SocketChannel channel = null;
try {
System.out.println("server 处理 read 事件...");
channel = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
int read = channel.read(buffer);
if (read > 0) {
String msg = new String(buffer.array(), StandardCharsets.UTF_8);
System.out.println("收到来自 " + channel.getRemoteAddress() + " 的消息 msg = " + msg);
// 讲消息发送给其他 client 端
sendOtherClient(channel, msg);
}
} catch (IOException e) {
if (channel != null) {
try {
System.out.println(channel.getRemoteAddress() + " 机器下线 ....");
// 取消注册 关闭通道
key.cancel();
channel.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
private void sendOtherClient(SocketChannel selfChannel, String msg) throws IOException {
System.out.println("server 正在转发 " + selfChannel.getRemoteAddress() + " 机器的消息.......");
for (SelectionKey key : selector.keys()) {
SelectableChannel channel = key.channel();
if (channel instanceof SocketChannel && channel != selfChannel) {
SocketChannel ch = (SocketChannel) channel;
ByteBuffer buffer = ByteBuffer.wrap(msg.getBytes(StandardCharsets.UTF_8));
ch.write(buffer);
System.out.println("server 将 " + selfChannel.getRemoteAddress() + " 的消息转发给 " + ch.getRemoteAddress());
}
}
}
public static void main(String[] args) {
System.out.println("server running........");
NioServer server = new NioServer();
server.listen();
}
}
3.7.3 client coding
public class NioClient {
private static final String HOST = "127.0.0.1";
private static final int PORT = 9099;
private Selector selector;
private SocketChannel socketChannel;
public NioClient() {
try {
selector = Selector.open();
socketChannel = SocketChannel.open(new InetSocketAddress(HOST, PORT));
socketChannel.configureBlocking(false);
socketChannel.register(selector, SelectionKey.OP_READ);
System.out.println(socketChannel.getLocalAddress() + " id ok...");
} catch (IOException e) {
e.printStackTrace();
}
}
public void handlerRead() {
try {
int select = selector.select();
if (select > 0) {
Set<SelectionKey> selectionKeys = selector.selectedKeys();
Iterator<SelectionKey> iterator = selectionKeys.iterator();
while (iterator.hasNext()) {
SelectionKey key = iterator.next();
if (key.isReadable()) {
SocketChannel channel = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
channel.read(buffer);
String msg = new String(buffer.array(), StandardCharsets.UTF_8);
System.out.println("client read msg : " + msg.trim());
}
iterator.remove();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void send(String msg) {
try {
msg = socketChannel.getLocalAddress() + " 发出的数据 " + msg;
socketChannel.write(ByteBuffer.wrap(msg.getBytes(StandardCharsets.UTF_8)));
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
System.out.println("client running...");
NioClient client = new NioClient();
new Thread(() -> {
while (true) {
client.handlerRead();
}
}).start();
Scanner scanner = new Scanner(System.in);
while (scanner.hasNextLine()) {
client.send(scanner.nextLine());
}
}
}