Looly 5 years ago
parent
commit
02b0f6194f

+ 3 - 1
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;
 }

+ 20 - 10
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;
 
 	/**
 	 * 构造
@@ -69,6 +72,17 @@ public abstract class NioClient implements Closeable {
 	}
 
 	/**
+	 * 设置NIO数据处理器
+	 *
+	 * @param handler {@link ChannelHandler}
+	 * @return this
+	 */
+	public NioClient setChannelHandler(ChannelHandler handler){
+		this.handler = handler;
+		return this;
+	}
+
+	/**
 	 * 开始监听
 	 */
 	public void listen() {
@@ -106,19 +120,15 @@ 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);
+			}
 		}
 	}
 
 	/**
-	 * 处理读事件<br>
-	 * 当收到读取准备就绪的信号后,回调此方法,用户可读取从客户端传出来的消息
-	 *
-	 * @param socketChannel SocketChannel
-	 */
-	protected abstract void read(SocketChannel socketChannel);
-
-	/**
 	 * 实现写逻辑<br>
 	 * 当收到写出准备就绪的信号后,回调此方法,用户可向客户端发送消息
 	 *

+ 7 - 1
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);
+			}
 		}
 	}
 

+ 24 - 33
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));
 			}
 		}
 	}

+ 6 - 12
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));
 	}
 }