https://www.hoshino.asia/archives/hutool

概述

模块介绍

Socket介绍

介绍来自:TCP编程

在开发网络应用程序的时候,我们又会遇到Socket这个概念。Socket是一个抽象概念,一个应用程序通过一个Socket来建立一个远程连接,而Socket内部通过TCP/IP协议把数据传输到网络。

Hutool封装

JDK中提供了Socket功能,包括:

  • BIO

  • NIO

  • AIO

Hutool只针对NIO和AIO做了简单的封装,用于简化Socket异步开发。

现阶段,Hutool的socket封装依旧不是一个完整框架或者高效的工具类,不能提供完整的高性能IO功能,因此推荐更加专业的Socket库。例如:

t-io

Voovan

Netty

Mina

AIO封装-AioServer和AioClient

由来

在JDK7+后,提供了异步Socket库——AIO,Hutool对其进行了简单的封装。

使用

服务端

AioServer aioServer = new AioServer(8899);
aioServer.setIoAction(new SimpleIoAction() {
	
	@Override
	public void accept(AioSession session) {
		StaticLog.debug("【客户端】:{} 连接。", session.getRemoteAddress());
		session.write(BufferUtil.createUtf8("=== Welcome to Hutool socket server. ==="));
	}
	
	@Override
	public void doAction(AioSession session, ByteBuffer data) {
		Console.log(data);
		
		if(false == data.hasRemaining()) {
			StringBuilder response = StrUtil.builder()//
					.append("HTTP/1.1 200 OK\r\n")//
					.append("Date: ").append(DateUtil.formatHttpDate(DateUtil.date())).append("\r\n")//
					.append("Content-Type: text/html; charset=UTF-8\r\n")//
					.append("\r\n")
					.append("Hello Hutool socket");//
			session.writeAndClose(BufferUtil.createUtf8(response));
		}else {
			session.read();
		}
	}
}).start(true);

客户端

final AsynchronousChannelGroup GROUP = AsynchronousChannelGroup.withFixedThreadPool(//
		Runtime.getRuntime().availableProcessors(), // 默认线程池大小
		ThreadFactoryBuilder.create().setNamePrefix("Huool-socket-").build()//
);

AsynchronousSocketChannel channel;
try {
	channel = AsynchronousSocketChannel.open(GROUP);
} catch (IOException e) {
	throw new IORuntimeException(e);
}
try {
	channel.connect(new InetSocketAddress("localhost", 8899)).get();
} catch (InterruptedException | ExecutionException e) {
	IoUtil.close(channel);
	throw new SocketRuntimeException(e);
}

AioClient client = new AioClient(channel, new SimpleIoAction() {
	
	@Override
	public void doAction(AioSession session, ByteBuffer data) {
		if(data.hasRemaining()) {
			Console.log(StrUtil.utf8Str(data));
			session.read();
		}
		Console.log("OK");
	}
});

client.write(ByteBuffer.wrap("Hello".getBytes()));
client.read();

client.close();

注意: GROUP维护一个连接池,建议全局单例持有。 见:issues/I56SYG

NIO封装-NioServer和NioClient

由来

Hutool对NIO其进行了简单的封装。

使用

服务端

NioServer server = new NioServer(8080);
server.setChannelHandler((sc)->{
	ByteBuffer readBuffer = ByteBuffer.allocate(1024);
	try{
		//从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();
			//eturns 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);
			doWrite(sc, body);
		} else if (readBytes < 0) {
			IoUtil.close(sc);
		}
	} catch (IOException e){
		throw new IORuntimeException(e);
	}
});
server.listen();
public static void doWrite(SocketChannel channel, String response) throws IOException {
	response = "收到消息:" + response;
	//将缓冲数据写入渠道,返回给客户端
	channel.write(BufferUtil.createUtf8(response));
}

客户端

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();
client.write(BufferUtil.createUtf8("你好。\n"));
client.write(BufferUtil.createUtf8("你好2。"));
// 在控制台向服务器端发送数据
Console.log("请输入发送的消息:");
Scanner scanner = new Scanner(System.in);
while (scanner.hasNextLine()) {
	String request = scanner.nextLine();
	if (request != null && request.trim().length() > 0) {
		client.write(BufferUtil.createUtf8(request));
	}
}

Ciallo~(∠・ω< )⌒☆