Netty:DelimiterBasedFrameDecoder分析

说明

io.netty.handler.codec.DelimiterBasedFrameDecoder是ByteToMessageDecoder的一个实现类,用一个或多个分割符拆分接收到的 ByteBuf。这个主要用于解析分隔符在帧的末尾的情况。注意,如果分割符在帧的开头,那么解析出来的帧的长度是0,所以要用在末尾的分隔符。
在构造DelimiterBasedFrameDecoder实例的时候,用到了下面几个参数,用来控制拆分行为:

  • maxFrameLength:拆分的帧最多有多少字节。
  • stripDelimiter:拆分后的帧是否去掉分隔符,默认值为true。
  • failFast:默认值为true。当为true的时候,如果解码器发现帧的长度大于maxFrameLength,就会抛出 TooLongFrameException,而不管是否真正读取了整个帧。如果值为false,实际读取的字节数大于maxFrameLength时,才会抛出TooLongFrameException。
  • delimiters:多个分割符。
  • delimiter:单个分割符。

代码示例

分割符在报文的结尾,正常解析

本示例验证的场景:

  • 客户端发送了一个12字节的报文给服务端。报文开头的字节内容是0x68,结尾的字节内容是0x16。
  • 服务端用了DelimiterBasedFrameDecoder来基于分隔符解析帧。解析的时候设置帧的最大字节数是12,去掉分隔符,分隔符是0x16。解析完成后,将去掉分隔符的帧传送给后面的ChannelHandler。

服务端代码片段

package com.thb.power.server;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;

/**
 * 服务端的主函数
 * @author thb
 *
 */
public class MainStation {
	private static final Logger logger = LogManager.getLogger();
	
	static final int PORT = Integer.parseInt(System.getProperty("port", "22335"));

	public static void main(String[] args) throws Exception {
		logger.traceEntry();
		
		// 配置服务器
		EventLoopGroup bossGroup = new NioEventLoopGroup();
		EventLoopGroup workerGroup = new NioEventLoopGroup();
		try {
			ServerBootstrap b =  new ServerBootstrap();
			b.group(bossGroup, workerGroup)
			 .channel(NioServerSocketChannel.class)
			 .option(ChannelOption.SO_BACKLOG, 100)
			 .handler(new LoggingHandler(LogLevel.INFO))
			 .childHandler(new MainStationInitializer());
			
			// 启动服务端
			ChannelFuture f = b.bind(PORT).sync();
			
			// 等待直到server socket关闭
			f.channel().closeFuture().sync();
		} finally {
			// 关闭所有event loops以便终止所有的线程
			bossGroup.shutdownGracefully();
			workerGroup.shutdownGracefully();
		}
		
		logger.traceExit();
	}

}
package com.thb.power.server;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import com.thb.power.server.register.ServerRegisterRequestHandler;

import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;

public class MainStationInitializer extends ChannelInitializer {
	private static final Logger logger = LogManager.getLogger();

	 @Override
	 public void initChannel(SocketChannel ch) throws Exception {
		 logger.traceEntry();
		 
		 ChannelPipeline p = ch.pipeline();		
		 
		 p.addLast(new LoggingHandler(LogLevel.INFO));
		 p.addLast(new DelimiterBasedFrameDecoder(12, true, Unpooled.wrappedBuffer(new byte[] {0x16})));
		 p.addLast(new ServerRegisterRequestHandler());
		 
		 logger.traceExit();
	 }
}
package com.thb.power.server.register;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

public class ServerRegisterRequestHandler extends ChannelInboundHandlerAdapter {
	
	private static final Logger logger = LogManager.getLogger();
	
	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg) {
		logger.traceEntry();
		
		ByteBuf m = (ByteBuf)msg;
		
		logger.info("readableBytes: " + m.readableBytes());
		logger.traceExit();
	}
	
	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
		cause.printStackTrace();
		ctx.close();
	}
}

启动服务端

Netty:DelimiterBasedFrameDecoder分析_第1张图片

启动客户端,并向服务端发送包含12个字节的报文

Netty:DelimiterBasedFrameDecoder分析_第2张图片

观察服务端的输出

Netty:DelimiterBasedFrameDecoder分析_第3张图片
从服务端的输出可以看到,ServerRegisterRequestHandler收到了11个字节的数据,这是正确的。因为整个帧12个字节,DelimiterBasedFrameDecoder在解析的时候,我们通过参数控制,去掉了1个字节的分隔符。

你可能感兴趣的:(Netty,java)