通过对DelimiterBasedFrameDecoder的使用,我们可以自动完成分隔符为结束标识的消息的解码。
下面的例子中,将$_作为分隔符。
服务端代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
|
public class { protected final static String DELIMITER = "$_"; public static void main(String[] args) { EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); ServerBootstrap b = new ServerBootstrap(); b.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .option(ChannelOption.SO_BACKLOG, 1024) .handler(new LoggingHandler(LogLevel.INFO)) .childHandler(new ChannelInitializer<SocketChannel>() { protected void initChannel(SocketChannel socketChannel) throws Exception { ByteBuf delimiter = Unpooled.copiedBuffer(DELIMITER.getBytes()); socketChannel.pipeline().addLast(new DelimiterBasedFrameDecoder(1024,delimiter)); socketChannel.pipeline().addLast(new StringDecoder()); socketChannel.pipeline().addLast(new EchoServerHandler()); } }); try { ChannelFuture f = b.bind(8899).sync(); f.channel().closeFuture().sync(); } catch (InterruptedException e) { e.printStackTrace(); } finally { bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } } } class EchoServerHandler extends ChannelHandlerAdapter { private int counter; public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { ctx.close(); } public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { String body = (String) msg; System.out.println("接收到客户端请求:" + body + ",counter=" + ++counter); body += EchoServer.DELIMITER; ByteBuf resp = Unpooled.copiedBuffer(body.getBytes()); ctx.write(resp); } public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { ctx.flush(); } }
|
客户端代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
|
public class EchoClient { protected final static String DELIMITER = "$_"; public static void main(String[] args) { EventLoopGroup group = new NioEventLoopGroup(); Bootstrap b = new Bootstrap(); b.group(group).channel(NioSocketChannel.class).option(ChannelOption.TCP_NODELAY,true).handler(new ChannelInitializer<SocketChannel>() { protected void initChannel(SocketChannel socketChannel) throws Exception { ByteBuf delimiter = Unpooled.copiedBuffer(DELIMITER.getBytes()); socketChannel.pipeline().addLast(new DelimiterBasedFrameDecoder(1024,delimiter)); socketChannel.pipeline().addLast(new StringDecoder()); socketChannel.pipeline().addLast(new EchoClientHandler()); } }); try { ChannelFuture f = b.connect("127.0.0.1",8899).sync(); f.channel().closeFuture().sync(); } catch (InterruptedException e) { e.printStackTrace(); } finally { group.shutdownGracefully(); } } }
class EchoClientHandler extends ChannelHandlerAdapter { private int counter = 0; public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { ctx.close(); } public void channelActive(ChannelHandlerContext ctx) throws Exception { String req = "hello,this message is from client."+EchoClient.DELIMITER; ByteBuf sendBuf = null; for (int i=0;i<100;i++) { sendBuf = Unpooled.copiedBuffer(req.getBytes()); ctx.writeAndFlush(sendBuf); } } @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { String resp = (String) msg; System.out.println("接收到服务端响应:" + resp + ",counter=" + ++counter); } }
|
参考《Netty权威指南》
原文:大专栏 DelimiterBasedFrameDecoder解决TCP粘包拆包问题