java NIO 实例之多人聊天
关键抽象
1.定义一个HashMap<String,SocketChannel>用户存储每个用户的管道。
2.服务端监听read事件,获取消息后轮询hashmap发送消息给用户模型内的所有用户
3.客户端简单read事件,读取聊天消息;发送消息给服务端
1.服务端代码
package com.leam.springboot.nio; 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.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.nio.charset.Charset; import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.UUID; /** * NIO服务端转发个所有客户端 */ public class NioServer { private static Selector selector; /** * 开启一个服务端 * 设置为非阻塞 * 绑定端口号 * backlog 处理的最大连接数,大于这个数直接拒绝 */ static { try { ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); serverSocketChannel.configureBlocking(false); serverSocketChannel.bind(new InetSocketAddress(9999)); selector = Selector.open(); serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); } catch (IOException e) { e.printStackTrace(); } } public static void server() throws IOException { Map<String, SocketChannel> clientMap = new HashMap<>(0); while (true) { selector.select(); Set<SelectionKey> selectionKeys = selector.selectedKeys(); selectionKeys.forEach(selectionKey -> { try { if (selectionKey.isAcceptable()) { /** * 服务器接收到客户端链接 * 保存接收到的客户端链接 */ ServerSocketChannel server = (ServerSocketChannel) selectionKey.channel(); SocketChannel channel = server.accept(); channel.configureBlocking(false); channel.register(selector, SelectionKey.OP_READ); String key = UUID.randomUUID().toString(); clientMap.put(key, channel); System.out.println(channel.getRemoteAddress() + "链接上服务器"); } else if (selectionKey.isReadable()) { /** * 读取客户端消息 * 转发到所有客户端 */ try { SocketChannel channel = (SocketChannel) selectionKey.channel(); ByteBuffer buffer = ByteBuffer.allocate(1024); int len = channel.read(buffer); if (len > 0) { buffer.flip(); Charset charset = Charset.forName("UTF-8"); String receiveMsg = String.valueOf(charset.decode(buffer).array()); String key = null; for (Map.Entry<String, SocketChannel> entry : clientMap.entrySet()) { if (entry.getValue() == channel) { key = entry.getKey(); break; } } String sendMsg = key + ":" + receiveMsg; System.out.println(sendMsg); for (Map.Entry<String, SocketChannel> entry : clientMap.entrySet()) { ByteBuffer writeBuffer = ByteBuffer.allocate(1024); writeBuffer.put(charset.encode(sendMsg)); writeBuffer.flip(); entry.getValue().write(writeBuffer); } } } catch (Exception e) { e.printStackTrace(); System.out.println("远程主机强迫关闭了一个现有的连接11111"); } } } catch (Exception e) { System.out.println("服务端出来异常"); } }); selectionKeys.clear(); } } public static void main(String args[]) throws IOException { server(); } }
2.客户端代码
package com.leam.springboot.nio; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; 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.HashMap; import java.util.Map; import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * 客户端注册 */ public class NioClient { private static Selector selector; /** * 开启一个服务端 * 设置为非阻塞 * 连接到服务器 */ static { try { SocketChannel socketChannel=SocketChannel.open(); socketChannel.configureBlocking(false); socketChannel.connect(new InetSocketAddress("localhost",9999)); selector=Selector.open(); socketChannel.register(selector, SelectionKey.OP_CONNECT); } catch (IOException e) { e.printStackTrace(); } } public static void client() throws IOException { Map<String,SocketChannel> clientMap=new HashMap<>(0); while (true) { selector.select(); Set<SelectionKey> selectionKeys=selector.selectedKeys(); selectionKeys.forEach( selectionKey -> { try { if (selectionKey.isConnectable()) { /** * 客户端已连接 * 开启一个线程监听控制台输入 */ SocketChannel client = (SocketChannel) selectionKey.channel(); if (client.isConnectionPending()) { client.finishConnect(); } client.register(selector,SelectionKey.OP_READ); // for(int i=0;i<5;i++){ ExecutorService executor = Executors.newSingleThreadExecutor(); System.out.println(client.getLocalAddress()+"连上了服务器"); ByteBuffer writeBuffer = ByteBuffer.allocate(1024); executor.submit(()->{ try { while (true) { writeBuffer.clear(); BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); String line = reader.readLine(); writeBuffer.put(line.getBytes()); writeBuffer.flip(); client.write(writeBuffer); } }catch (Exception e) { e.printStackTrace(); } }); // } } else if (selectionKey.isReadable()) { /** * 打印服务端消息 */ SocketChannel client = (SocketChannel) selectionKey.channel(); ByteBuffer readBuffer = ByteBuffer.allocate(1024); int len = client.read(readBuffer); System.out.println(new String(readBuffer.array(),0,len)); } } catch (Exception e) { e.printStackTrace(); } }); selectionKeys.clear(); } } public static void main(String args[]) throws IOException { client(); } }

浙公网安备 33010602011771号