LineBasedFrameDecoder换行解码器

发表时间:2017-10-26 13:54:04 浏览量( 27 ) 留言数( 0 )

学习目标:

1、了解LineBasedFrameDecoder

2、能通过LineBasedFrameDecoder编写代码


学习过程:

一、LineBasedFrameDecoder解码器

    LineBasedFrameDecoder是回车换行解码器,如果用户发送的消息以回车换行符\r作为消息结束的标识,则可以直接使用Netty的LineBasedFrameDecoder对消息进行解码,只需要在初始化Netty服务端或者客户端时将LineBasedFrameDecoder正确的添加到ChannelPipeline中即可,不需要自己重新实现一套换行解码器。LineBasedFrameDecoder也可以指定最大的长度,如果超出长度会报出异常,具体的大家自己看一些LineBasedFrameDecoder的源代码。

    本节课还会使用到StringDecoder,这个比较简单就是直接转换成为字符串。

二、示例代码

(1)自定义服务器端的Handler

public class LineServerHandler extends ChannelInboundHandlerAdapter {
	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg) {
		
		String body=(String)msg;
		
		System.out.println("服务端收到的信息:"+body);
		
		String cuTime="Server Time:"+new Date()+"\r\n";
		
		ByteBuf resp=Unpooled.copiedBuffer(cuTime.getBytes());
		
		ctx.writeAndFlush(resp);
		
	}

	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
		cause.printStackTrace();
		ctx.close();
	}
}

(2)启动类

public class LineServer {
	private int port;

	public LineServer(int port) {
		this.port = port;
	}

	public void run() throws Exception {
		EventLoopGroup bossGroup = new NioEventLoopGroup(); 
		EventLoopGroup workerGroup = new NioEventLoopGroup();
		try {
			ServerBootstrap b = new ServerBootstrap(); 
			b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class) 
					.childHandler(new ChannelInitializer<SocketChannel>() { 
						@Override
						public void initChannel(SocketChannel ch) throws Exception {
							ch.pipeline().addLast(new LineBasedFrameDecoder(2048),new StringDecoder(), new LineServerHandler());
						}
					}).option(ChannelOption.SO_BACKLOG, 128) 
					.childOption(ChannelOption.SO_KEEPALIVE, true); 

			// 绑定端口,开始接收进来的连接
			ChannelFuture f = b.bind(port).sync(); 

			// 等待服务器 socket 关闭 。
			// 在这个例子中,这不会发生,但你可以优雅地关闭你的服务器。
			f.channel().closeFuture().sync();
		} finally {
			workerGroup.shutdownGracefully();
			bossGroup.shutdownGracefully();
		}
	}

	public static void main(String[] args) throws Exception {
		int port;
		if (args.length > 0) {
			port = Integer.parseInt(args[0]);
		} else {
			port = 8084;
		}
		new LineServer(port).run();
	}

}

    启动类里面我们在pipleline添加了两个解码器,也就是在我们自定义的业务Handler收到信息之前,信息已经经过解码了,所以我们可以直接在Handler中获得的就是字符串了。然后Handler会回发一条信息给客户端,注意每一条信息最后都必须带有换行符的。


客户端代码

(1)自定义客户端的Handler

public class LineClientHandler extends ChannelInboundHandlerAdapter {
	
	@Override
	public void channelActive(ChannelHandlerContext ctx) {
		
		System.out.println("LineClientHandler:channelActive");
		
		for(int i=0;i<100;i++) {
			String cuTime="client :"+i+"\r\n";
			ByteBuf resp=Unpooled.buffer(cuTime.getBytes().length);
			resp.writeBytes(cuTime.getBytes());
			ctx.writeAndFlush(resp);
		}
	}

	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg) {
		String body = (String) msg;

		System.out.println("客户端收到的信息:" + body);

	}

	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
		cause.printStackTrace();
		ctx.close();
	}
}

(2)客户端启动类。

public class LineClient {
	public static void main(String[] args) throws Exception {

		String host ="localhost";
		int port = 8084;
		EventLoopGroup workerGroup = new NioEventLoopGroup();

		try {
			Bootstrap b = new Bootstrap(); 
			b.group(workerGroup); 
			b.channel(NioSocketChannel.class); 
			b.option(ChannelOption.SO_KEEPALIVE, true); 
			b.handler(new ChannelInitializer<SocketChannel>() {
				@Override
				public void initChannel(SocketChannel ch) throws Exception {
					ch.pipeline().addLast(new LineBasedFrameDecoder(2048),new StringDecoder(),new LineClientHandler());
				}
			});

			// 启动客户端
			ChannelFuture f = b.connect(host, port).sync(); // (5)

			// 等待连接关闭
			f.channel().closeFuture().sync();
		} finally {
			workerGroup.shutdownGracefully();
		}
	}
}

先启动服务端,在启动客户端,两边在接受数据时都没有发生错误。