netty 拆包粘包(LineBasedFrameDecoder)

netty 拆包粘包,也就是半包读写问题。

之前有说过,主要是三种解决方案,一个是消息定长,一个是分隔符,一个是将消息分为消息头消息体。

之前说到分隔符的时候,主要说的是DelimiterBasedFrameDecoderDelimiterBasedFrameDecoder可以指定任意一个分隔符,注意,它的分隔符要放在前面。

今天要讲的是LineBasedFrameDecoder,LineBasedFrameDecoder也属于分隔符的范畴,不过LineBasedFrameDecoder的分隔符限定是换行符\n,而且是放在消息尾的。而且要配合StringDecoder使用。

关键部分1 配置handler时:

 //添加拆包粘包解码器
        pipeline.addLast(new LineBasedFrameDecoder(1024));
        pipeline.addLast(new StringDecoder());
关键部分2 发送消息时:

future.channel().writeAndFlush(Unpooled.copiedBuffer(("你好"+System.getProperty("line.separator")).getBytes()));
System.getProperty("line.separator")就是添加的分隔符。


有个细节要注意,就是new LineBasedFrameDecoder(1024) 这里的1024是啥意思?意思就是如果消息长度到了1024还没有发现换行符,那么就异常了,消息也就收不到了。所以这个值一定要大于消息的长度,尽量大一些。

下面看具体代码:

server 端三个:

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;

public class LineServer {

    public void bind() {
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workGroup = new NioEventLoopGroup();
        ServerBootstrap bootstrap = new ServerBootstrap();
        bootstrap.group(bossGroup, workGroup);
        bootstrap.channel(NioServerSocketChannel.class)
                .option(ChannelOption.SO_BACKLOG, 1024)
                .option(ChannelOption.SO_SNDBUF, 32 * 1024)
                .option(ChannelOption.SO_RCVBUF, 32 * 1024)
                .option(ChannelOption.SO_KEEPALIVE, true)
                .handler(new LoggingHandler(LogLevel.DEBUG))
                .childHandler(new LineServerInitialzer());

        try {

            ChannelFuture future = bootstrap.bind("127.0.0.1", 8765).sync();
            future.channel().closeFuture().sync();
            bossGroup.shutdownGracefully();
            workGroup.shutdownGracefully();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

    public static void main(String[] args) {
        new LineServer().bind();
    }
}


import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.handler.codec.LineBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;

public class LineServerInitialzer extends ChannelInitializer {

    protected void initChannel(Channel ch) throws Exception {
        ChannelPipeline pipeline = ch.pipeline();
        //添加拆包粘包解码器
        pipeline.addLast(new LineBasedFrameDecoder(1024));
        pipeline.addLast(new StringDecoder());
        pipeline.addLast(new LineServerHandler());
    }
}



public class LineServerHandler extends ChannelHandlerAdapter {
    private Log logger= LogFactory.getLog(LineServerHandler.class);
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        logger.error("server erro",cause);
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        logger.info("---------------server active-----------");
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        logger.info("---------------server inActive-----------");
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        logger.info("---------------server read-----------");
        String rev_msg= (String) msg;
        logger.info("server read:"+rev_msg);

    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        ctx.close();
    }
}



Client端 三个

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;

public class LineClient {

    public void connect(){
        EventLoopGroup workGroup=new NioEventLoopGroup();
        Bootstrap bootstrap=new Bootstrap();
        bootstrap.group(workGroup);
        bootstrap.channel(NioSocketChannel.class)
                .handler(new LineClientInitializer())
                .handler(new LoggingHandler(LogLevel.DEBUG));
        try {
        ChannelFuture future= bootstrap.connect("127.0.0.1",8765).sync();
        for(int i=0;i<10;i++){
            future.channel().writeAndFlush(Unpooled.copiedBuffer(("你好"+System.getProperty("line.separator")).getBytes()));
        }
        future.channel().closeFuture().sync();
        workGroup.shutdownGracefully();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        new LineClient().connect();
    }
}

import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.handler.codec.LineBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;

public class LineClientInitializer extends ChannelInitializer {
    protected void initChannel(Channel ch) throws Exception {
        ChannelPipeline pipeline=ch.pipeline();
        pipeline.addLast(new LineBasedFrameDecoder(1024));
        pipeline.addLast(new StringDecoder());
        pipeline.addLast(new LineClientHandler());
    }
}

import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class LineClientHandler extends ChannelHandlerAdapter {
    private Log logger= LogFactory.getLog(LineClientHandler.class);
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        logger.error("client erro",cause);
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        logger.info("---------------client active-----------");
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        logger.info("----------------client inActive----------");
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        logger.info("----------------client read---------------");
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
    }
}
 


猜你喜欢

转载自blog.csdn.net/liyuan0323/article/details/79297546