Java NIO - 群聊

服务端

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你好啊
你好你好
本作品采用《CC 协议》,转载必须注明作者和本文链接
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!