java基于NIO实现群聊模式

 更新时间:2021年11月24日 08:32   作者:林夕$相心
这篇文章主要为大家详细介绍了java实现NIO实现群聊模式,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

本文实例为大家分享了java基于NIO实现群聊模式的具体代码,供大家参考,具体内容如下

Client

package com.qst.chat;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Scanner;

public class GroupChatClient {
 private final int PORT = 9999;
 private final String HOST = "localhost";
 private SocketChannel channel;
 private static Selector selector;

 private String name;
 
 public GroupChatClient() throws IOException {

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

  System.out.println(name + "is ok ....");

 }
 // 向服务器发送消息
 public void sendTO(String msg) {
  
  ByteBuffer buffer = ByteBuffer.wrap((name+":"+msg).getBytes());
  try {
   channel.write(buffer);
  } catch (IOException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }

 }
 // 读取从服务器端回复的消息
 public static void getInfo() {
  
  try {
   if(selector.select() >0) {
    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 len;
     
     // 把读到的缓冲区的数据转成字符串
     while((len = sc.read(buffer)) > 0) {
      System.out.println(new String(buffer.array()));
     }
     
     }
  
     
    }
    // 删除当前的selectionKey, 防止重复操作
    iterator.remove();
    
   }
  } catch (IOException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
  
 }
 
 public static void main(String[] args) {
  try {
   GroupChatClient client = new GroupChatClient();
   
   
   new Thread() {
    
    
    public void run() {
     while(true)
     {
      try {
       Thread.sleep(3000);
       GroupChatClient.getInfo();
      } catch (InterruptedException e) {
       // TODO Auto-generated catch block
       e.printStackTrace();
      }
     }
     
    };
   }.start();
   
   
   Scanner sc = new Scanner(System.in);
//   while(true) {
//    String name = sc.nextLine();
//    client.sendTO(name);
//   }
   while(sc.hasNextLine()) {
      String s = sc.nextLine();
              client.sendTO(s);
   }
   
  } catch (IOException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
 }

}

Server端

package com.qst.chat;

import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.time.chrono.IsoChronology;
import java.util.Iterator;

import com.sun.accessibility.internal.resources.accessibility;

import sun.print.resources.serviceui;

public class GroupChatServer {

 private static ServerSocketChannel socketChannel;
 private static Socket socket;
 private static Selector selector;
 private static SocketChannel accept;

 public GroupChatServer() throws IOException {

  socketChannel = ServerSocketChannel.open();

  selector = Selector.open();
  // 绑定端口
  socketChannel.socket().bind(new InetSocketAddress(9999));
  // 设置非阻塞模式
  socketChannel.configureBlocking(false);

  // 将该通道 注册到selector
  socketChannel.register(selector, SelectionKey.OP_ACCEPT);

 }

 // 监听
 public static void listen() {
  System.out.println("监听线程: " + Thread.currentThread().getName());
  try {
   while (selector.select() > 0) {

    Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();

    if (iterator.hasNext()) {
     // 遍历得到selectionKey 集合
     SelectionKey next = iterator.next();
     if (next.isAcceptable()) {
      next.channel();
      // socketChannel = (ServerSocketChannel) next.channel();
      SocketChannel accept = socketChannel.accept();
      accept.configureBlocking(false);

      accept.register(selector, SelectionKey.OP_READ);

       System.out.println(accept.getRemoteAddress()+" 上线 了。。。");
     }
     if (next.isReadable()) {
      readDate(next);

     }

     // 移除当前的next,防止重复处理
     iterator.remove();
     // System.out.println("未发现");

    }

   }
  } catch (IOException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }

 }

 // 读取客户端消息
 public static void readDate(SelectionKey key) {

  try {
   accept = (SocketChannel) key.channel();
   ByteBuffer buffer = ByteBuffer.allocate(1024);
   int len = accept.read(buffer);
   if (len > 0) {
    buffer.flip();
    String msg = new String(buffer.array());
    System.out.println("user = " + msg);

    // 向其它的客户端转发消息(去掉自己)
    sendToAll(msg, accept);
    buffer.clear();
   }
  } catch (IOException e) {
   // TODO Auto-generated catch block
   try {
    String msg = accept.getRemoteAddress().toString();
    // 取消注册
    key.cancel();
    // 关闭通道
    accept.close();
    System.out.println(msg + "离线了");
   } catch (IOException e1) {
    // TODO Auto-generated catch block
    e1.printStackTrace();
   }
   // e.printStackTrace();
  } finally {
   // TODO: handle finally clause
  }
 }

 public static void sendToAll(String msg, SocketChannel ssc) {
  for (SelectionKey ss : selector.keys()) {
   // 通过 key 取出对应的 SocketChannel
   SelectableChannel channel = ss.channel();

   // 排除自己
   if (channel instanceof SocketChannel && channel != ssc) {
    // 转型
    SocketChannel sh = (SocketChannel) channel;
    // 转存到buffer
    ByteBuffer wrap = ByteBuffer.wrap(msg.getBytes());
    try {
     // 写入通道
     sh.write(wrap);
    } catch (IOException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }
   }
  }
 }

 public static void main(String[] args) throws IOException {
  GroupChatServer server = new GroupChatServer();
  GroupChatServer.listen();

 }

}

key.isAcceptable()进行接入 操作的时候, 获取通道有两种方式

1、 通过selector获取 (Selector key) socketChannel = (ServerSocketChannel) key.channel();
建立连接 socketChannel .accept();

2、定义一个全局变量

在进行初始化的时候,存储(socketChannel = ServerSocketChannel.open();)
建立连接 socketChannel .accept();

key.isReadable() 当进行到读入操作的时候( ) SelectionKey key accept = (SocketChannel) key.channel();

演示

服务器启动,客户端启动


客户端发送消息

启动第二个客户端

两个客户端相互通信

离线信息显示

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持猪先飞。

原文出处:https://tanghao.blog.csdn.net/article/details/115718260

相关文章

  • Java如何发起http请求的实现(GET/POST)

    这篇文章主要介绍了Java如何发起http请求的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-03-31
  • 在java中获取List集合中最大的日期时间操作

    这篇文章主要介绍了在java中获取List集合中最大的日期时间操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-08-15
  • Java中 % 与Math.floorMod() 区别详解

    这篇文章主要介绍了Java中 % 与Math.floorMod() 区别详解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-08-20
  • Java生成随机姓名、性别和年龄的实现示例

    这篇文章主要介绍了Java生成随机姓名、性别和年龄的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-10-01
  • java 判断两个时间段是否重叠的案例

    这篇文章主要介绍了java 判断两个时间段是否重叠的案例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-08-15
  • 解决Java处理HTTP请求超时的问题

    这篇文章主要介绍了解决Java处理HTTP请求超时的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-03-29
  • 浅谈Java与C#的一些细微差别

    说起C#和Java这两门语言(语法,数据类型 等),个人以为,大概有90%以上的相似,甚至可以认为几乎一样。但是在工作中,我也发现了一些细微的差别...2020-06-25
  • java代码获取jenkins数据,构建历史等信息方式

    这篇文章主要介绍了java代码获取jenkins数据,构建历史等信息方式,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-05-12
  • Java数据结构之哈夫曼树概述及实现

    文中详细讲了关于Java哈夫曼树的概述以及用Java实现的方法,对各位正在学习java数据结构的小伙伴们有很大的帮助哟,需要的朋友可以参考下...2021-05-14
  • Java连接数据库oracle中文乱码解决方案

    这篇文章主要介绍了Java连接数据库oracle中文乱码解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下...2020-05-16
  • Java匿名内部类的写法示例

    这篇文章主要给大家介绍了关于Java匿名内部类的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-08-31
  • 一篇文章带你使用SpringBoot基于WebSocket的在线群聊实现

    这篇文章主要介绍了一篇文章带你使用SpringBoot基于WebSocket的在线群聊实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-10-08
  • Java面试题冲刺第十五天--设计模式

    这篇文章主要为大家分享了最有价值的三道关于设计模式的面试题,涵盖内容全面,包括数据结构和算法相关的题目、经典面试编程题等,感兴趣的小伙伴们可以参考一下...2021-08-07
  • Java开发实现人机猜拳游戏

    这篇文章主要介绍了Java开发实现人机猜拳游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-08-03
  • 在java中使用SPI创建可扩展的应用程序操作

    这篇文章主要介绍了在java中使用SPI创建可扩展的应用程序操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-09-14
  • Java 创建并应用PPT幻灯片母版的方法示例

    幻灯片母版可供用户设置幻灯片的样式,本文将介绍如何用Java创建并应用单个或多个幻灯片母版。感兴趣可以了解一下...2020-06-04
  • Java中的Pair详细

    这篇文章主要介绍Java中的很有意思的Pair,下面文章会以Pair用法展开,感兴趣的小伙伴可以参考下面文章的具体内容...2021-10-08
  • Java中的abstract和interface

    abstract和interface关键字在Java中随处可见,它是Java三大特性封装、继承、多态特性的实现重要支柱之一。interface关键字用于定义接口抽象,其本质上是用于定义类型、定义类所具有的能力,下面来看看详细内容,需要的朋友可以参考一下...2021-11-03
  • 详解Java后端优雅验证参数合法性

    这篇文章主要介绍了详解Java后端优雅验证参数合法性,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-02-18
  • Java核心技术巩固篇之控制流程与大数值及数组详解

    该文章主要补充了一些大家可能没有了解的、重要的、易忘记的知识点,其实并不是用来专门学习 Java 的文章,而是主要用来帮助大家巩固自己的内功的,有需要的朋友跟着小编往下看吧...2021-10-25