Java NIO聊天室代码

85 篇文章 1 订阅
28 篇文章 0 订阅

在这里插入图片描述

服务端

public class Server {
    //backlog为accept队列大小,默认值为50
    private static final int BACKLOG = 1024;
    private static final String IP = "127.0.0.1";
    private static final int PORT = 8888;
    private ServerSocketChannel serverChannel;
    private Selector selector;

    //构造函数
    public Server() {
        try {
            //打开服务端通道
            serverChannel = ServerSocketChannel.open();
            //设置非阻塞
            serverChannel.configureBlocking(false);
            //绑定端口,在服务端监听
            serverChannel.bind(new InetSocketAddress(IP, PORT), BACKLOG);
            //打开选择器
            selector = Selector.open();
            //把服务端通道注册到选择器,关注的事件是接收
            serverChannel.register(selector, SelectionKey.OP_ACCEPT);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {

        }
    }

    //监听客户端
    public void listen() {
        try {
            //循环等待客户端连接
            for (; ; ) {
                int readChannel = selector.select();
//                if (selector.select(1000) == 0) {
//                    System.out.println("无连接,服务器等待...");
//                    continue;
//                }
                if (readChannel > 0) {
                    //关注事件集合
                    Set<SelectionKey> selectionKeys = selector.selectedKeys();
                    Iterator<SelectionKey> iterator = selectionKeys.iterator();
                    while (iterator.hasNext()) {
                        SelectionKey key = iterator.next();
                        //如果是OP_ACCEPT,有新的客户端连接
                        if (key.isAcceptable()) {
                            SocketChannel channel = serverChannel.accept();
                            channel.configureBlocking(false);
                            //关联buffer
                            //channel.register(selector, SelectionKey.OP_READ, ByteBuffer.allocate(1024));
                            //把通道注册到选择器,关注的事件是读
                            channel.register(selector, SelectionKey.OP_READ);
                            System.out.println(channel.getRemoteAddress() + "上线了...");
                        }
                        if (key.isReadable()) {
                            readClient(key);
                        }
                        //移除Selection,因为多线程,要防止重复操作
                        iterator.remove();
                    }
                } else {
                    System.out.println("没有可用通道!");
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {

        }
    }

    //读取客户端
    private void readClient(SelectionKey key) {
        SocketChannel channel = null;
        try {
            channel = (SocketChannel) key.channel();
            //获取buffer
            //ByteBuffer buffer = (ByteBuffer) key.attachment();
            //ByteBuffer buffer = ByteBuffer.wrap(str.getBytes());
            ByteBuffer buffer = ByteBuffer.allocate(1024);
            //把通道数据放入缓冲区
            int count = channel.read(buffer);
            if (count > 0) {
                String msg = new String(buffer.array());
                System.out.println("客户端:" + msg);
                //转发到其他客户端
                sendClient(msg, channel);
            }
        } catch (IOException e) {
            try {
                System.out.println(channel.getRemoteAddress() + "离线了...");
                //取消注册
                key.cancel();
                //关闭通道
                channel.close();
            } catch (IOException ioException) {
                ioException.printStackTrace();
            }
        } finally {

        }
    }

    //转发给其他客户端,也就是给通道发(排除自己)
    private void sendClient(String msg, SocketChannel self) throws IOException {
        //遍历所有注册到选择器的通道,并排除自己
        for (SelectionKey key : selector.keys()) {
            Channel targetChannel = key.channel();
            //排除自己
            if (targetChannel instanceof SocketChannel && targetChannel != self) {
                //转型
                SocketChannel dest = (SocketChannel) targetChannel;
                ByteBuffer buffer = ByteBuffer.wrap(msg.getBytes());
                //把缓冲区数据放入通道
                dest.write(buffer);
            }
        }
    }

    public static void main(String[] args) throws Exception {
        Server server = new Server();
        server.listen();
    }
}

客户端

public class Client {
    private static final String IP = "127.0.0.1";
    private static final int PORT = 8888;
    private SocketChannel channel;
    private Selector selector;
    private String user;

    //构造函数
    public Client() throws IOException {
        //打开服务端通道
        channel = SocketChannel.open(new InetSocketAddress(IP, PORT));
        //设置非阻塞
        channel.configureBlocking(false);
        //打开选择器
        selector = Selector.open();
        //把通道注册到选择器,关注的事件是读
        channel.register(selector, SelectionKey.OP_READ);
        user = channel.getLocalAddress().toString();
        System.out.println(user + "已连接...");
    }

    //向服务器发送消息
    private void sendServer(String msg) {
        msg = user + ":" + msg;
        ByteBuffer buffer = ByteBuffer.wrap(msg.getBytes());
        //把缓冲区数据放入通道
        try {
            channel.write(buffer);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //读取服务器消息
    private void readServer() {
        try {
            //for (; ; ) {
            int readChannel = selector.select();
            //判断有效通道
            if (readChannel > 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();
                        channel.configureBlocking(false);
                        ByteBuffer buffer = ByteBuffer.allocate(1024);
                        //把通道数据放入缓冲区
                        channel.read(buffer);
                        System.out.println(new String(buffer.array()));
                    }
                    //移除Selection,因为多线程,要防止重复操作
                    iterator.remove();
                }
            } else {
                System.out.println("没有可用通道!");
            }
            //}
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws Exception {
        Client client = new Client();
        //client.readServer();
        //每隔2秒,读取服务端数据
        new Thread(() -> {
            while (true) {
                client.readServer();
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();

        //发送数据给服务端
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNextLine()) {
            String s = scanner.nextLine();
            client.sendServer(s);
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值