Java NIO实战之多人聊天室

作者:红字V 时间:2022-02-28 15:05:00 

本文实例为大家分享了Java NIO实战之多人聊天室的具体代码,供大家参考,具体内容如下

NIO服务端


public class NioServer {

/**
    * 启动
    */
   public void start() throws IOException {
       /**
        * 1. 创建Selector
        */
       Selector selector = Selector.open();
       /**
        * 2. 通过ServerSocketChannel创建channel通道
        */
       ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
       /**
        * 3. 为channel通道绑定监听端口
        */
       serverSocketChannel.bind(new InetSocketAddress(8000));
       /**
        * 4. **设置channel为非阻塞模式**
        */
       serverSocketChannel.configureBlocking(false);
       /**
        * 5. 将channel注册到selector上,监听连接事件
        */
       serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
       System.out.println("服务器启动成功!");

/**
        * 6. 循环等待新接入的连接
        */
       for (;;) { // while(true) c for;;
           /**
            * TODO 获取可用channel数量
            */
           int readyChannels = selector.select();

/**
            * TODO 为什么要这样!!?
            */
           if (readyChannels == 0) continue;

/**
            * 获取可用channel的集合
            */
           Set<SelectionKey> selectionKeys = selector.selectedKeys();

Iterator iterator = selectionKeys.iterator();

while (iterator.hasNext()) {
               /**
                * selectionKey实例
                */
               SelectionKey selectionKey = (SelectionKey) iterator.next();

/**
                * **移除Set中的当前selectionKey**
                */
               iterator.remove();

/**
                * 7. 根据就绪状态,调用对应方法处理业务逻辑
                */
               /**
                * 如果是 接入事件
                */
               if (selectionKey.isAcceptable()) {
                   acceptHandler(serverSocketChannel, selector);
               }

/**
                * 如果是 可读事件
                */
               if (selectionKey.isReadable()) {
                   readHandler(selectionKey, selector);
               }
           }
       }
   }

/**
    * 接入事件处理器
    */
   private void acceptHandler(ServerSocketChannel serverSocketChannel,
                              Selector selector)
           throws IOException {
       /**
        * 如果要是接入事件,创建socketChannel
        */
       SocketChannel socketChannel = serverSocketChannel.accept();

/**
        * 将socketChannel设置为非阻塞工作模式
        */
       socketChannel.configureBlocking(false);

/**
        * 将channel注册到selector上,监听 可读事件
        */
       socketChannel.register(selector, SelectionKey.OP_READ);

/**
        * 回复客户端提示信息
        */
       socketChannel.write(Charset.forName("UTF-8")
               .encode("你与聊天室里其他人都不是朋友关系,请注意隐私安全"));
   }

/**
    * 可读事件处理器
    */
   private void readHandler(SelectionKey selectionKey, Selector selector)
           throws IOException {
       /**
        * 要从 selectionKey 中获取到已经就绪的channel
        */
       SocketChannel socketChannel = (SocketChannel) selectionKey.channel();

/**
        * 创建buffer
        */
       ByteBuffer byteBuffer = ByteBuffer.allocate(1024);

/**
        * 循环读取客户端请求信息
        */
       String request = "";
       while (socketChannel.read(byteBuffer) > 0) {
           /**
            * 切换buffer为读模式
            */
           byteBuffer.flip();

/**
            * 读取buffer中的内容
            */
           request += Charset.forName("UTF-8").decode(byteBuffer);
       }

/**
        * 将channel再次注册到selector上,监听他的可读事件
        */
       socketChannel.register(selector, SelectionKey.OP_READ);

/**
        * 将客户端发送的请求信息 广播给其他客户端
        */
       if (request.length() > 0) {
           // 广播给其他客户端
           broadCast(selector, socketChannel, request);
       }
   }

/**
    * 广播给其他客户端
    */
   private void broadCast(Selector selector,
                          SocketChannel sourceChannel, String request) {
       /**
        * 获取到所有已接入的客户端channel
        */
       Set<SelectionKey> selectionKeySet = selector.keys();

/**
        * 循环向所有channel广播信息
        */
       selectionKeySet.forEach(selectionKey -> {
           Channel targetChannel = selectionKey.channel();

// 剔除发消息的客户端
           if (targetChannel instanceof SocketChannel
                   && targetChannel != sourceChannel) {
               try {
                   // 将信息发送到targetChannel客户端
                   ((SocketChannel) targetChannel).write(
                           Charset.forName("UTF-8").encode(request));
               } catch (IOException e) {
                   e.printStackTrace();
               }
           }
       });
   }

/**
    * 主方法
    * @param args
    */
   public static void main(String[] args) throws IOException {
       new NioServer().start();
   }

}

NIO客户端


public class NioClient {

/**
    * 启动
    */
   public void start(String nickname) throws IOException {
       /**
        * 连接服务器端
        */
       SocketChannel socketChannel = SocketChannel.open(
               new InetSocketAddress("127.0.0.1", 8000));

/**
        * 接收服务器端响应
        */
       // 新开线程,专门负责来接收服务器端的响应数据
       // selector , socketChannel , 注册
       Selector selector = Selector.open();
       socketChannel.configureBlocking(false);
       socketChannel.register(selector, SelectionKey.OP_READ);
       new Thread(new NioClientHandler(selector)).start();

/**
        * 向服务器端发送数据
        */
       Scanner scanner = new Scanner(System.in);
       while (scanner.hasNextLine()) {
           String request = scanner.nextLine();
           if (request != null && request.length() > 0) {
               socketChannel.write(
                       Charset.forName("UTF-8")
                               .encode(nickname + " : " + request));
           }
       }

}
   public static void main(String[] args) throws IOException {
//        new NioClient().start();
   }
}

客户端线程,处理服务器端响应的的消息


public class NioClientHandler implements Runnable {
   private Selector selector;

public NioClientHandler(Selector selector) {
       this.selector = selector;
   }

@Override
   public void run() {

try {
           for (;;) {
               int readyChannels = selector.select();

if (readyChannels == 0) continue;

/**
                * 获取可用channel的集合
                */
               Set<SelectionKey> selectionKeys = selector.selectedKeys();

Iterator iterator = selectionKeys.iterator();

while (iterator.hasNext()) {
                   /**
                    * selectionKey实例
                    */
                   SelectionKey selectionKey = (SelectionKey) iterator.next();

/**
                    * **移除Set中的当前selectionKey**
                    */
                   iterator.remove();

/**
                    * 7. 根据就绪状态,调用对应方法处理业务逻辑
                    */

/**
                    * 如果是 可读事件
                    */
                   if (selectionKey.isReadable()) {
                       readHandler(selectionKey, selector);
                   }
               }
           }
       } catch (IOException e) {
           e.printStackTrace();
       }
   }

/**
    * 可读事件处理器
    */
   private void readHandler(SelectionKey selectionKey, Selector selector)
           throws IOException {
       /**
        * 要从 selectionKey 中获取到已经就绪的channel
        */
       SocketChannel socketChannel = (SocketChannel) selectionKey.channel();

/**
        * 创建buffer
        */
       ByteBuffer byteBuffer = ByteBuffer.allocate(1024);

/**
        * 循环读取服务器端响应信息
        */
       String response = "";
       while (socketChannel.read(byteBuffer) > 0) {
           /**
            * 切换buffer为读模式
            */
           byteBuffer.flip();

/**
            * 读取buffer中的内容
            */
           response += Charset.forName("UTF-8").decode(byteBuffer);
       }

/**
        * 将channel再次注册到selector上,监听他的可读事件
        */
       socketChannel.register(selector, SelectionKey.OP_READ);

/**
        * 将服务器端响应信息打印到本地
        */
       if (response.length() > 0) {
           System.out.println(response);
       }
   }
}

我们定义三个客户端,模拟三个用户在聊天室发送消息


public class AClient {

public static void main(String[] args)
           throws IOException {
       new NioClient().start("AClient");
   }
}

public class BClient {

public static void main(String[] args)
           throws IOException {
       new NioClient().start("BClient");
   }
}

public class CClient {

public static void main(String[] args)
           throws IOException {
       new NioClient().start("CClient");
   }

}

NIO 聊天室到此结束

来源:https://blog.csdn.net/sinat_36899414/article/details/106169245

标签:java,NIO,聊天室
0
投稿

猜你喜欢

  • java中synchronized锁的升级过程

    2023-12-01 13:14:51
  • C#实现生成mac地址与IP地址注册码的两种方法

    2022-07-14 20:14:58
  • 浅析Android代码质量管理

    2021-06-18 23:02:03
  • C#中foreach原理以及模拟的实现

    2022-04-07 23:18:12
  • C#实现改变DataGrid某一行和单元格颜色的方法

    2022-08-23 20:45:22
  • 进度条ProgressBar及ProgressDialog(实例)

    2021-09-24 01:07:42
  • Java Web实现session过期后自动跳转到登陆页功能【基于过滤器】

    2021-08-19 03:44:37
  • WPF自动隐藏的消息框的实例代码

    2023-09-11 09:52:36
  • 基于SpringBoot+Redis实现分布式锁

    2023-10-16 11:44:31
  • Java求解两个非负整数最大公约数算法【循环法与递归法】

    2021-10-15 13:53:48
  • string boot 与 自定义interceptor的实例讲解

    2023-10-27 17:03:20
  • Java文件与IO流操作原理详细分析

    2023-08-12 13:13:46
  • Java中static关键字的作用和用法详细介绍

    2022-07-05 08:33:53
  • 基于java.lang.IllegalArgumentException异常报错问题及解决

    2023-09-14 16:03:34
  • Android 中CheckBox多项选择当前的position信息提交的示例代码

    2022-05-15 19:13:51
  • Unity3d 如何更改Button的背景色

    2023-10-02 15:48:39
  • springboot集成opencv实现人脸识别功能的详细步骤

    2023-10-07 00:38:22
  • 深入解析C语言中常数的数据类型

    2021-09-03 11:02:18
  • Java线程池 ThreadPoolExecutor 详解

    2021-05-24 10:35:42
  • spring-boot整合ehcache实现缓存机制的方法

    2023-06-18 20:05:10
  • asp之家 软件编程 m.aspxhome.com