当前位置: 首页 > 工具软件 > IM_Java > 使用案例 >

Java NIO - 简单群聊

咸弘雅
2023-12-01

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你好啊
你好你好

 类似资料: