NIO简单实现群聊系统

服务端:

public class NioServer {
    public static void main(String[] args) throws IOException {
        NioServer nioServer = new NioServer();
        nioServer.nioDemo9();
    }

    private Selector selector;
    private ServerSocketChannel serverSocketChannel;

    public NioServer() throws IOException {
        //先新建ServerSocketChannel来监听端口
        serverSocketChannel = ServerSocketChannel.open();
        //设置为非阻塞
        serverSocketChannel.configureBlocking(false);
        //新建一个Selector
        selector = Selector.open();
        //开始监听端口
        InetSocketAddress inetSocketAddress = new InetSocketAddress(6666);
        //监听端口
        serverSocketChannel.socket().bind(inetSocketAddress);
        //然后把ServerSocketChannel注册到selector中,并关心事件为accept
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
    }

    public  void nioDemo9() throws IOException {
        //开始进行监听后的操作,轮询等待客户端
        while(true){
            //判断是否有正在发生事件的通道
            if (selector.select(1000)==0){
                System.out.println("服务等待了一秒钟,无连接");
                continue;
            }
            //如果返回的是大于0 ,则获取相关的selectionKey集合
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            //对这些key遍历进行业务操作

            selectionKeys.stream().forEach(selectionKey -> {
                //如果改key是注册的意思,就先对其进行注册,处理连接
                if (selectionKey.isAcceptable()){
                    try {
                        //创建一个socketchannel为客户端所用
                        SocketChannel socketChannel = serverSocketChannel.accept();
                        System.out.println("有客户端进行连接:"+socketChannel.hashCode());
                        socketChannel.configureBlocking(false);
                        //需要把socketchannel也注册到selector上
                        socketChannel.register(selector,SelectionKey.OP_READ, ByteBuffer.allocate(1024));
                        System.out.println(socketChannel.getRemoteAddress()+"上线");
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }if (selectionKey.isReadable()){
                    //通道发生read事件,通道可读状态
                    //如果是可读的事件,则对其进行读取
                    try {
                        //通过selectionKey来得到channel
                        SocketChannel channel = (SocketChannel)selectionKey.channel();
                        //通过selectionKey来得到buffer
                        ByteBuffer attachment = (ByteBuffer)selectionKey.attachment();
                        //将buffer的数据读到channel
                        channel.read(attachment);
                        String str = new String(attachment.array());
                        //写一个方法用来将信息发给其他客户端
                        System.out.println("from 客户端"+str);
                        sendMsg(channel,str);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
    }

    public  void sendMsg(SocketChannel self,String msg){
        //得到所有的key
        Set<SelectionKey> selectionKeys = selector.selectedKeys();

        selectionKeys.stream().forEach(key->{
            //根据key得到Channel
            Channel channel = key.channel();
            //然后判断是否为本socketchannel
            SocketChannel socketChannel = (SocketChannel) channel;
            if (self!=socketChannel){
               if (self instanceof SocketChannel) {
                   ByteBuffer byteBuffer = ByteBuffer.wrap(msg.getBytes());
                   try {
                       socketChannel.write(byteBuffer);
                   } catch (IOException e) {
                       e.printStackTrace();
                   }
               }
            }else{
                System.out.println("没有其他客户端进行连接");
            }
        });
    }
}

客户端:

public class NioClient {
    // 定义相关的属性
    private static final String HOST = "127.0.0.1"; // 服务器ip地址
    private static final int PORT = 6666; // 服务器端口
    private Selector selector;
    private SocketChannel socketChannel;
    private String userName;
 private static    ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(3, 5, 2, TimeUnit.SECONDS, new ArrayBlockingQueue<>(2));
 
    public NioClient() {
        try {
            this.selector = Selector.open();
            // 连接服务器
            socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", PORT));
            // 设置非阻塞
            socketChannel.configureBlocking(false);
            // 将 channel 注册到 selector,事件 READ
            socketChannel.register(this.selector, SelectionKey.OP_READ);
            // 得到userName
            userName = socketChannel.getLocalAddress().toString().substring(1);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    public static void main(String[] args) throws IOException {
        // 启动客户端
        NioClient client = new NioClient();
        threadPoolExecutor.execute(new Runnable() {
            @Override
            public void run() {
            while(true){
                try {
                   // client.read();
                    client.send("test");
                    TimeUnit.SECONDS.sleep(3);
                } catch (Exception e) {
                    e.printStackTrace();
                    break;
                }
             }
            }
        });

    }

    private static void nioDemo10() throws IOException {
        //新建一个客户端使用的socketchannel
        SocketChannel socketChannel = SocketChannel.open();
        //设置为非阻塞channel
        socketChannel.configureBlocking(false);
        //连接上服务端的6666端口
        InetSocketAddress socketAddress = new InetSocketAddress("127.0.0.1", 6666);
        //开始连接
        boolean connect = socketChannel.connect(socketAddress);
        if (!connect) {
            //没连接上,然后判断连接是否已经中断,如果还没有中断,则提示
            while (!socketChannel.finishConnect()) {
                System.out.println("连接还未中断,可以进行其他操作");
            }
        } else {
            //连接成功,开始发送信息
            String str = "客户端发送信息为1";
            //这里ByteBuffer提供了一个方法,避免了资源浪费,以往是使用allocal方法来开启一个有大小的buffer
            //这里的wrap方法是可以根据byte数组的大小来定义buffer的大小的,这样不会造成资源浪费
            ByteBuffer byteBuffer = ByteBuffer.wrap(str.getBytes());
            //nio里面的传输数据,就是把buffer里面的数据,写入到channel就行了
            socketChannel.write(byteBuffer);
            System.in.read();
        }

    }

    /**
     * 发送数据到服务器
     * @param msg
     */
    private void send(String msg) {
        msg = userName + ":" + msg;
        ByteBuffer buffer = ByteBuffer.wrap(msg.getBytes(StandardCharsets.UTF_8));
        try {
            socketChannel.write(buffer);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    /**
     * @description 从通道读取数据并显示
     * @author
     * @date
     */
    private void read() throws IOException {
        selector.select();
        // 存在可用通道,读取数据并显示 (注意这里是 selector.selectedKeys() 而不是 selector.keys() )
        Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
        while (iterator.hasNext()) {
            SelectionKey key = iterator.next();
            // 若可读通道,则读取
            if (key.isReadable()) {
                SocketChannel sc = (SocketChannel) key.channel();
                ByteBuffer buffer = ByteBuffer.allocate(1024);
                int count = sc.read(buffer);
                System.out.println(new String(buffer.array(), 0, count , StandardCharsets.UTF_8));
            }
            // 用完key要移除
            iterator.remove();
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值