NIO群聊Demo
服务器端代码
package com.pw.datastructure.nio.groupChat; import java.io.IOException; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.nio.ByteBuffer; import java.nio.channels.*; import java.util.Iterator; import java.util.Set; /** * @author pw * @version 1.0 * @date 2022/9/13 9:29 */ public class GroupChatServer { // 定义相关的属性 /** * nio选择器 */ private Selector selector; /** * 做监听 */ private ServerSocketChannel listenChannel; /** * 端口 */ private static final int PORT = 6667; // 构造器,初始化任务 public GroupChatServer() { try { // 1. 得到选择器 selector = Selector.open(); // 2. 创建socket服务通道 listenChannel = ServerSocketChannel.open(); // 3. 绑定端口 listenChannel.socket().bind(new InetSocketAddress(PORT)); // 4.设置listenChannel为非阻塞通道 listenChannel.configureBlocking(false); // 5. 将listenChannel注册进selector 设置监听的事件是 ACCEPT (客户端连接时) listenChannel.register(selector, SelectionKey.OP_ACCEPT); System.out.println(); } catch (IOException e) { e.printStackTrace(); } } // 监听 public void listen (){ try { while (true){ int count = selector.select(); if (count > 0){ // 有事件要处理 // 遍历selectionKey集合 Iterator<SelectionKey> iterator = selector.selectedKeys().iterator(); while (iterator.hasNext()){ // 取出SelectionKey SelectionKey key = iterator.next(); // 监听到连接事件 if (key.isAcceptable()){ // 1. 拿到SocketChannel SocketChannel sc = listenChannel.accept(); // 2. 将SocketChannel设置非阻塞 sc.configureBlocking(false); // 3. SocketChannel注册 sc.register(selector,SelectionKey.OP_READ, ByteBuffer.allocate(1024)); System.out.println(sc.getRemoteAddress() + " 上线"); } // 监听到读取事件 if (key.isReadable()){ readData(key); } // 当前的key操作完成后,从集合中删除,防止多线程同时操作同一个key iterator.remove(); } }else { // 无事件处理 System.out.println("等待。。。。。。"); } } } catch (IOException e) { e.printStackTrace(); } finally { } } // 读取客户端消息 public void readData (SelectionKey key){ // 定义一个 SocketChannel channel = null ; try { // 取到关联的channel channel = (SocketChannel) key.channel(); // 创建一个缓冲区 ByteBuffer buffer = ByteBuffer.allocate(1024); int count = channel.read(buffer); // 判断是否读取到数据 if (count > 0){ // 读取到数据 String msg = new String(buffer.array()); // 服务端收到消息,输出消息 System.out.println("form 客户端:" + msg); // 向其他的客户端转发消息 sendInfoToOtherClients(msg ,channel); } }catch (IOException e){ // 在读的过程中,client端断连了 try { System.out.println(channel.getRemoteAddress() + "离线。。。"); // 取消注册 key.cancel(); // 关闭通道 channel.close(); } catch (IOException ex) { ex.printStackTrace(); } } } // 转发消息给其他客户端(通道发消息) public void sendInfoToOtherClients (String msg, SocketChannel self) throws IOException{ System.out.println("服务器转发消息中。。。"); // 遍历所有注册到selector 上SocketChannel,并且排除自己 for (SelectionKey item : selector.keys()) { // 通过key取出对应的SocketChannel Channel targetChannel = item.channel(); if (targetChannel instanceof SocketChannel && targetChannel != self){ // 转发 ((SocketChannel) targetChannel).write(ByteBuffer.wrap(msg.getBytes())); } } } public static void main(String[] args) { //创建一个服务器对象 GroupChatServer groupChatServer = new GroupChatServer(); groupChatServer.listen(); } }
客户端代码
package com.pw.datastructure.nio.groupChat; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SelectableChannel; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.SocketChannel; import java.util.Iterator; import java.util.Scanner; import java.util.Set; /** * @author pw * @version 1.0 * @date 2022/9/13 10:20 */ public class GroupChatClient { /** * 服务器的ip */ private static final String HOST = "127.0.0.1"; /** * 端口 */ private static final int SERVER_PORT = 6667; /** * 选择器 */ private Selector selector; /** * 通道 */ private SocketChannel socketChannel; /** * 客户端自己的地址 */ private String clientHost; public GroupChatClient (){ try { selector = Selector.open(); // 连接服务器 socketChannel = socketChannel.open(new InetSocketAddress(HOST,SERVER_PORT)); // 设置非阻塞 socketChannel.configureBlocking(false); // 注册 socketChannel.register(selector, SelectionKey.OP_READ); // 客户端自己的地址 clientHost = socketChannel.getLocalAddress().toString().substring(1); System.out.println(clientHost + "客户端已准备。。。"); } catch (IOException e) { e.printStackTrace(); } } // 向服务器发送消息 public void sendInfo (String msg){ msg = clientHost + "发送了:" + msg; try { socketChannel.write(ByteBuffer.wrap(msg.getBytes())); }catch (IOException e){ e.printStackTrace(); } } // 从服务器端读取消息 public void readInfo (){ try { int readCount = selector.select(); if (readCount > 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); sc.read(buffer); System.out.println(new String(buffer.array())); } } iterator.remove(); } }catch (IOException e){ e.printStackTrace(); } } public static void main(String[] args) { // 1. 启动客户端 GroupChatClient groupChatClient = new GroupChatClient(); // 2. 启动一个线程 new Thread(){ @Override public void run() { while (true){ // 每隔三秒读取服务器端发送的数据 groupChatClient.readInfo(); try { Thread.currentThread().sleep(3000); }catch (InterruptedException e){ e.printStackTrace(); } } } }.start(); // 客户端发送数据给服务器端 Scanner scanner = new Scanner(System.in); while (scanner.hasNextLine()){ String msg = scanner.nextLine(); groupChatClient.sendInfo(msg); } } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?