diff --git a/hutool-socket/src/main/java/cn/hutool/socket/nio/ChannelHandler.java b/hutool-socket/src/main/java/cn/hutool/socket/nio/ChannelHandler.java index 84a9d1e7f..248b8a734 100644 --- a/hutool-socket/src/main/java/cn/hutool/socket/nio/ChannelHandler.java +++ b/hutool-socket/src/main/java/cn/hutool/socket/nio/ChannelHandler.java @@ -6,12 +6,14 @@ import java.nio.channels.SocketChannel; * NIO数据处理接口,通过实现此接口,可以从{@link SocketChannel}中读写数据 * */ +@FunctionalInterface public interface ChannelHandler { /** * 处理NIO数据 * * @param socketChannel {@link SocketChannel} + * @throws Exception 可能的处理异常 */ - void handle(SocketChannel socketChannel); + void handle(SocketChannel socketChannel) throws Exception; } diff --git a/hutool-socket/src/main/java/cn/hutool/socket/nio/NioClient.java b/hutool-socket/src/main/java/cn/hutool/socket/nio/NioClient.java index 07a3de382..738f9c584 100644 --- a/hutool-socket/src/main/java/cn/hutool/socket/nio/NioClient.java +++ b/hutool-socket/src/main/java/cn/hutool/socket/nio/NioClient.java @@ -3,6 +3,7 @@ package cn.hutool.socket.nio; import cn.hutool.core.io.IORuntimeException; import cn.hutool.core.io.IoUtil; import cn.hutool.core.thread.ThreadUtil; +import cn.hutool.socket.SocketRuntimeException; import java.io.Closeable; import java.io.IOException; @@ -19,9 +20,11 @@ import java.util.Iterator; * @author looly * @since 4.4.5 */ -public abstract class NioClient implements Closeable { +public class NioClient implements Closeable { + private Selector selector; private SocketChannel channel; + private ChannelHandler handler; /** * 构造 @@ -68,6 +71,17 @@ public abstract class NioClient implements Closeable { return this; } + /** + * 设置NIO数据处理器 + * + * @param handler {@link ChannelHandler} + * @return this + */ + public NioClient setChannelHandler(ChannelHandler handler){ + this.handler = handler; + return this; + } + /** * 开始监听 */ @@ -106,18 +120,14 @@ public abstract class NioClient implements Closeable { // 读事件就绪 if (key.isReadable()) { final SocketChannel socketChannel = (SocketChannel) key.channel(); - read(socketChannel); + try{ + handler.handle(socketChannel); + } catch (Exception e){ + throw new SocketRuntimeException(e); + } } } - /** - * 处理读事件
- * 当收到读取准备就绪的信号后,回调此方法,用户可读取从客户端传出来的消息 - * - * @param socketChannel SocketChannel - */ - protected abstract void read(SocketChannel socketChannel); - /** * 实现写逻辑
* 当收到写出准备就绪的信号后,回调此方法,用户可向客户端发送消息 diff --git a/hutool-socket/src/main/java/cn/hutool/socket/nio/NioServer.java b/hutool-socket/src/main/java/cn/hutool/socket/nio/NioServer.java index 2ce10cc33..632bb2b44 100644 --- a/hutool-socket/src/main/java/cn/hutool/socket/nio/NioServer.java +++ b/hutool-socket/src/main/java/cn/hutool/socket/nio/NioServer.java @@ -3,6 +3,7 @@ package cn.hutool.socket.nio; import cn.hutool.core.io.IORuntimeException; import cn.hutool.core.io.IoUtil; import cn.hutool.log.Log; +import cn.hutool.log.StaticLog; import java.io.Closeable; import java.io.IOException; @@ -135,7 +136,12 @@ public class NioServer implements Closeable { // 读事件就绪 if (key.isReadable()) { final SocketChannel socketChannel = (SocketChannel) key.channel(); - handler.handle(socketChannel); + try{ + handler.handle(socketChannel); + } catch (Exception e){ + IoUtil.close(socketChannel); + StaticLog.error(e); + } } } diff --git a/hutool-socket/src/test/java/cn/hutool/socket/nio/NioClientTest.java b/hutool-socket/src/test/java/cn/hutool/socket/nio/NioClientTest.java index a39f04f40..e993e4bb3 100644 --- a/hutool-socket/src/test/java/cn/hutool/socket/nio/NioClientTest.java +++ b/hutool-socket/src/test/java/cn/hutool/socket/nio/NioClientTest.java @@ -1,58 +1,49 @@ package cn.hutool.socket.nio; +import cn.hutool.core.io.BufferUtil; import cn.hutool.core.lang.Console; -import cn.hutool.core.util.CharsetUtil; import cn.hutool.core.util.StrUtil; import lombok.SneakyThrows; import java.nio.ByteBuffer; -import java.nio.channels.SocketChannel; import java.util.Scanner; public class NioClientTest { @SneakyThrows public static void main(String[] args) { - NioClient client = new NioClient("127.0.0.1", 8080) { - - @SneakyThrows - @Override - protected void read(SocketChannel sc) { - ByteBuffer readBuffer = ByteBuffer.allocate(1024); - //从channel读数据到缓冲区 - int readBytes = sc.read(readBuffer); - if (readBytes > 0) { - //Flips this buffer. The limit is set to the current position and then - // the position is set to zero,就是表示要从起始位置开始读取数据 - readBuffer.flip(); - //returns the number of elements between the current position and the limit. - // 要读取的字节长度 - byte[] bytes = new byte[readBuffer.remaining()]; - //将缓冲区的数据读到bytes数组 - readBuffer.get(bytes); - String body = StrUtil.utf8Str(bytes); - Console.log("the read client receive message: " + body); - } else if (readBytes < 0) { - sc.close(); - } + NioClient client = new NioClient("127.0.0.1", 8080); + client.setChannelHandler((sc)->{ + ByteBuffer readBuffer = ByteBuffer.allocate(1024); + //从channel读数据到缓冲区 + int readBytes = sc.read(readBuffer); + if (readBytes > 0) { + //Flips this buffer. The limit is set to the current position and then + // the position is set to zero,就是表示要从起始位置开始读取数据 + readBuffer.flip(); + //returns the number of elements between the current position and the limit. + // 要读取的字节长度 + byte[] bytes = new byte[readBuffer.remaining()]; + //将缓冲区的数据读到bytes数组 + readBuffer.get(bytes); + String body = StrUtil.utf8Str(bytes); + Console.log("[{}]: {}", sc.getRemoteAddress(), body); + } else if (readBytes < 0) { + sc.close(); } - }; + }); client.listen(); - ByteBuffer buffer = ByteBuffer.wrap("client 发生到 server".getBytes()); - client.write(buffer); - buffer = ByteBuffer.wrap("client 再次发生到 server".getBytes()); - client.write(buffer); + client.write(BufferUtil.createUtf8("你好。\n")); + client.write(BufferUtil.createUtf8("你好2。")); // 在控制台向服务器端发送数据 - Console.log("请在下方畅所欲言"); + Console.log("请输入发送的消息:"); Scanner scanner = new Scanner(System.in); while (scanner.hasNextLine()) { String request = scanner.nextLine(); if (request != null && request.trim().length() > 0) { - client.write( - CharsetUtil.CHARSET_UTF_8 - .encode("测试client" + ": " + request)); + client.write(BufferUtil.createUtf8(request)); } } } diff --git a/hutool-socket/src/test/java/cn/hutool/socket/nio/NioServerTest.java b/hutool-socket/src/test/java/cn/hutool/socket/nio/NioServerTest.java index 53212ed37..f1d74b3ea 100644 --- a/hutool-socket/src/test/java/cn/hutool/socket/nio/NioServerTest.java +++ b/hutool-socket/src/test/java/cn/hutool/socket/nio/NioServerTest.java @@ -1,5 +1,6 @@ package cn.hutool.socket.nio; +import cn.hutool.core.io.BufferUtil; import cn.hutool.core.io.IORuntimeException; import cn.hutool.core.io.IoUtil; import cn.hutool.core.lang.Console; @@ -28,7 +29,8 @@ public class NioServerTest { //将缓冲区的数据读到bytes数组 readBuffer.get(bytes); String body = StrUtil.utf8Str(bytes); - Console.log("the read server receive message: " + body); + Console.log("[{}]: {}", sc.getRemoteAddress(), body); + doWrite(sc, body); } else if (readBytes < 0) { IoUtil.close(sc); @@ -41,16 +43,8 @@ public class NioServerTest { } public static void doWrite(SocketChannel channel, String response) throws IOException { - response = "我们已收到消息:" + response; - if (!StrUtil.isBlank(response)) { - byte[] bytes = response.getBytes(); - //分配一个bytes的length长度的ByteBuffer - ByteBuffer write = ByteBuffer.allocate(bytes.length); - //将返回数据写入缓冲区 - write.put(bytes); - write.flip(); - //将缓冲数据写入渠道,返回给客户端 - channel.write(write); - } + response = "收到消息:" + response; + //将缓冲数据写入渠道,返回给客户端 + channel.write(BufferUtil.createUtf8(response)); } } \ No newline at end of file