netty5.0通过LineBasedFrameDecoder和StringDecoder解决粘包

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.LineBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;

/**
 * server 粘包问题通过LineBasedFrameDecoder、StringDecoder解决
 * @author 
 *
 */
public class TimeServer {
	public void bind(int port) {
		 // 服务器线程组 用于网络事件的处理 一个用于服务器接收客户端的连接
        // 另一个线程组用于处理SocketChannel的网络读写
		EventLoopGroup bossGroup = new NioEventLoopGroup();
		EventLoopGroup workerGroup = new NioEventLoopGroup();
		
		try {
			 //NIO服务器端的辅助启动类 降低服务器开发难度
			ServerBootstrap b = new ServerBootstrap();
			b.group(bossGroup, workerGroup)
			 .channel(NioServerSocketChannel.class)    // 类似NIO中serverSocketChannel
			 .option(ChannelOption.SO_BACKLOG, 1024)   // 配置TCP参数
			 .childHandler(new ChildChannelHandler()); // 最后绑定I/O事件的处理类
			// 服务器启动后 绑定监听端口 同步等待成功 主要用于异步操作的通知回调 回调处理用的ChildChannelHandler
			ChannelFuture f = b.bind(port).sync();
			System.out.println("The time Server is start : "+port);
            // 等待服务端监听端口关闭
			f.channel().closeFuture().sync();
		} catch (InterruptedException e) {
			e.printStackTrace();
		} finally{
			// 优雅退出 释放线程池资源
			workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
            System.out.println("服务器优雅的释放了线程资源...");
		}
	}
	
	/**
	 * 网络事件处理器
	 * @author
	 *
	 */
	private class ChildChannelHandler extends ChannelInitializer<SocketChannel> {
		@Override
		protected void initChannel(SocketChannel ch) throws Exception {
			ch.pipeline().addLast(new LineBasedFrameDecoder(1024));
			ch.pipeline().addLast(new StringDecoder());  //设置字符串解码器 自动将报文转为字符串
			ch.pipeline().addLast(new TimeServerHandler());
		}
	}
	
	public static void main(String[] args) {
		int port = 8080;
		
		if(null != args && args.length > 0) {
			try {
				port = Integer.parseInt(args[0]);
			} catch (NumberFormatException e) {
				e.printStackTrace();
			}
		}
		
		new TimeServer().bind(port);
	}
}
import java.util.Date;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;

/**
 * server端网络IO事件处理
 * @author 
 *
 */
public class TimeServerHandler extends ChannelHandlerAdapter {
	
	private int counter;

	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg)
			throws Exception {
		System.out.println("服务器读取到客户端请求...");
		String body = (String)msg;
		System.out.println("The time server receive order :"+body+";the counter is "+ ++counter);
		String currentTime = "QUERY TIME ORDER".equalsIgnoreCase(body) ? new Date(System.currentTimeMillis()).toString() : "BAD ORDER";
		currentTime = currentTime + System.getProperty("line.separator");
		ByteBuf resp = Unpooled.copiedBuffer(currentTime.getBytes());
		ctx.writeAndFlush(resp);
		System.out.println("服务器做出了响应");
	}

	@Override
	public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
		ctx.flush();
		System.out.println("服务器readComplete 响应完成");
	}

	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
			throws Exception {
		ctx.close();
		System.out.println("服务器异常退出"+cause.getMessage());
	}
}
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.LineBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;

/**
 * client 粘包问题通过LineBasedFrameDecoder、StringDecoder解决
 * @author 
 *
 */
public class TimeClient {

	/**
	 * 连接服务器
	 * @param host
	 * @param port
	 */
	public void connect(String host, int port) {
		//配置客户端nio线程组
		EventLoopGroup group = new NioEventLoopGroup();
		
		try {
			//客户端辅助启动类 对客户端配置
			Bootstrap b = new Bootstrap();
			b.group(group).channel(NioSocketChannel.class)
			 .option(ChannelOption.TCP_NODELAY, true)
			 .handler(new ChannelInitializer<SocketChannel>() {
				@Override
				protected void initChannel(SocketChannel ch) throws Exception {
					ch.pipeline().addLast(new LineBasedFrameDecoder(1024));
					ch.pipeline().addLast(new StringDecoder());
					ch.pipeline().addLast(new TimeClientHandler());
				}
			 });
			//异步链接服务器 同步等待链接成功
			 ChannelFuture f = b.connect(host, port).sync();
			//等待链接关闭
			 f.channel().closeFuture().sync();
		} catch (InterruptedException e) {
			e.printStackTrace();
		} finally{
			group.shutdownGracefully();
			System.out.println("客户端优雅的释放了线程资源...");
		}
	}

	public static void main(String[] args) {
		int port = 8080;
		if(null != args && args.length > 0) {
			try {
				port = Integer.parseInt(args[0]);
			} catch (NumberFormatException e) {
				e.printStackTrace();
			}
		}
		
		new TimeClient().connect("127.0.0.1", port);
	}
}
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;

import java.util.logging.Logger;

/**
 * Client 网络IO事件处理
 * @author
 *
 */
public class TimeClientHandler extends ChannelHandlerAdapter {
	
	private static final Logger logger = Logger.getLogger(TimeClientHandler.class.getName());
	
	private int counter;
	
	private byte[] req;
	
	public TimeClientHandler() {
		req = ("QUERY TIME ORDER" + System.getProperty("line.separator")).getBytes();
	}
	
	@Override
	public void channelActive(ChannelHandlerContext ctx) throws Exception {
		ByteBuf message = null;
		for(int i=0; i<100; i++) {
			message = Unpooled.buffer(req.length);
			message.writeBytes(req);
			ctx.writeAndFlush(message);
		}
		logger.info("客户端active");
	}

	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg)
			throws Exception {
		logger.info("客户端收到服务器响应数据");
		String body = (String)msg;
		System.out.println("Now is : "+body+"; the counter is : "+ ++counter);
	}
	
	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
			throws Exception {
		logger.warning("Unexpected exception from downstream:"+cause.getMessage());
		ctx.close();
		System.out.println("客户端异常退出");
	}
	
}


你可能感兴趣的:(netty5.0通过LineBasedFrameDecoder和StringDecoder解决粘包)