NIO实现群聊

74 阅读2分钟

功能说明:

  1. 编写NIO群聊系统。实现服务器端和客户端的数据简单通信
  2. 实现多人群聊
  3. 服务器端:可以检测用户上限,离线,并实现消息转发功能
  4. 客户端:通过channel可以无阻塞的发消息给用户,同时可以接受其他用户发送的消息

服务器端:

    private Selector selector;
    private static final int PORT = 6667;

    //构造器  初始化
    public ChatServer() {
        try {
            selector = Selector.open();
            listenChannel = ServerSocketChannel.open();
            //绑定端口
            listenChannel.socket().bind(new InetSocketAddress(PORT));
            //设置非阻塞
            listenChannel.configureBlocking(false);
            //注册到selector
            listenChannel.register(selector, SelectionKey.OP_ACCEPT);


        } catch (Exception e) {
            e.getStackTrace();
        }

    }

    //监听
    private void listen() {
        try {
            //循环处理
            while (true) {
                int count = selector.select();
                if (count > 0) {  //有事件处理
                    Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
                    while (iterator.hasNext()) {
                        SelectionKey key = iterator.next();
                        if (key.isAcceptable()) {
                            SocketChannel socketChannel = listenChannel.accept();
                            socketChannel.configureBlocking(false);
                            socketChannel.register(selector, SelectionKey.OP_READ);

                            //提示
                            System.out.println(socketChannel.getRemoteAddress() + "上线");
                        }
                        if (key.isReadable()) {
                            //处理读
                            readData(key);
                        }
                        iterator.remove();
                    }
                }
            }
        } catch (Exception e) {
            e.getStackTrace();
        }

    }

    //读取客户端消息
    private void readData(SelectionKey key) {

        try {
            //得到通道 创建buffer
            SocketChannel channel = (SocketChannel) key.channel();
            ByteBuffer byteBuffer = ByteBuffer.allocate(1024);

            int read = channel.read(byteBuffer);
            if(read>0){
                String s = new String(byteBuffer.array());
                //输出消息
                System.out.println("form 客户端"+s);

                //向其他的客户端转发消息(除了自己)
                sendDataToOther(s,channel);
            }
        } catch (Exception e) {
            e.getStackTrace();
        }

    }

    private void sendDataToOther(String s,SocketChannel socketChannel) throws IOException {
        System.out.println("服务器转发消息中");
        //遍历 所有注册到selector上的socketchannel 并排除自己
        for (SelectionKey key : selector.keys()) {
            //通过key 取得对应的socketchannel
            SocketChannel channel = (SocketChannel)key.channel();

            //排除自己
            if(channel instanceof  SocketChannel && channel!=socketChannel){

                //将 消息 存储到buffer
                ByteBuffer byteBuffer = ByteBuffer.wrap(s.getBytes());
                //将buffer写入通道
                channel.write(byteBuffer);
            }
        }
    }


    public static void main(String[] args) {
//创建服务器对象
        ChatServer chatServer = new ChatServer();
        chatServer.listen();
    }

客户端:

      //启动客户端
        ChatClient chatClient=new ChatClient();
        new Thread(){
            @Override
            public void run() {
                while (true){

                    try {
                        chatClient.readData();
                        Thread.sleep(3000);
                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        }.start();
        //发送数据到 服务端
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNextLine()){
            String s = scanner.nextLine();
            chatClient.sendData(s);
        }

    }


    //定义相关属性
    private final String HOST = "127.0.0.1";
    private final int PORT = 6667;
    private Selector selector;

    private SocketChannel socketChannel;

    private String userName;

    //构造器 完成初始化工作

    public ChatClient() throws Exception {


        selector = Selector.open();
        //连接 服务器
        socketChannel = SocketChannel.open(new InetSocketAddress(HOST, PORT));
        //设置非阻塞
        socketChannel.configureBlocking(false);
        //将channel 注册到 selector
        socketChannel.register(selector, SelectionKey.OP_READ);
        //得到userName
        userName = socketChannel.getLocalAddress().toString().substring(1);

        System.out.println(userName + " is ok..........");
    }

    public void sendData(String info) {

        try {
            info = userName + "说:" + info;
            socketChannel.write(ByteBuffer.wrap(info.getBytes()));
        } catch (Exception e) {
            e.getStackTrace();
        }

    }

    public void readData() throws IOException {
        int count = selector.select();

        if (count > 0) {
            Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
            while (iterator.hasNext()) {
                SelectionKey key = iterator.next();
                if (key.isReadable()) {
                    //得到通道
                    SocketChannel channel = (SocketChannel) key.channel();
                    //得到一个buffer
                    ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
                    //读取
                    channel.read(byteBuffer);
                    //把读到的缓冲区里面的数据 转成字符串
                    String s = new String(byteBuffer.array());
                    System.out.println(s.trim());
                }
            }
            iterator.remove();
        }
    }