7 netty网络篇,netty拆包粘包和自定义协议

概况

​  本篇文章会在应用层面分享一下netty怎么方便的解决拆包和粘包问题,和我会分享一个最常用于解决拆包和粘包的方案自定义协议的demo,其中还会涉及到自定义编解码器,这个以后有时间再分享

拆包粘包

 ​ 解决拆包和粘包,最常见的方案有三种。

​  1 消息定长,每个报文长度固定,如果不够,空位补0;

 ​ 2 使用分隔符,报文间使用分隔符识别;

​  3 使用自定义协议,将消息分为消息头,和消息体,消息头记录着消息体的长度。



​  netty提供很方便的handler实现上面的方案,其中

 ​ 1 DelimiterBasedFrameDecoder —> 以分隔符为流结束的解码器

 ​ 2 FixedLengthFrameDecoder ---->定长解码器

自定义协议

​ ​ 自定义协议是netty解决拆包粘包比较好的实践,下面我把例子的代码黏贴出来


实体类:

package org.example.protocoltcp;

public class MessageBean {

    private int len;
    private byte[] content;

    public int getLen() {
        return len;
    }

    public void setLen(int len) {
        this.len = len;
    }

    public byte[] getContent() {
        return content;
    }

    public void setContent(byte[] content) {
        this.content = content;
    }
}


解码器:

package org.example.protocoltcp;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ReplayingDecoder;

import java.util.List;

public class MessageBeanDecoder extends ReplayingDecoder {
    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        int length = in.readInt();

        byte[] content = new byte[length];
        in.readBytes(content);

        MessageBean messageProtocol = new MessageBean();
        messageProtocol.setLen(length);
        messageProtocol.setContent(content);
        out.add(messageProtocol);
    }
}


编码器:

package org.example.protocoltcp;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;

public class MessageBeanEncoder extends MessageToByteEncoder<MessageBean> {
    @Override
    protected void encode(ChannelHandlerContext ctx, MessageBean msg, ByteBuf out) throws Exception {
        out.writeInt(msg.getLen());
        out.writeBytes(msg.getContent());
    }
}


客户端:

package org.example.protocoltcp;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;

public class NettyClient {

    public static void main(String[] args) {
        EventLoopGroup group = new NioEventLoopGroup(8);

        try{
            Bootstrap bootstrap = new Bootstrap();

            bootstrap.group(group)
                    .channel(NioSocketChannel.class)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ch.pipeline()
                                    .addLast(new MessageBeanEncoder())
                                    .addLast(new MessageBeanDecoder())
                                    .addLast(new NettyClientHandler());
                        }
                    });


            ChannelFuture channelFuture =
                    bootstrap.connect("127.0.0.1",6668).sync();

            channelFuture.channel().closeFuture().sync();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            group.shutdownGracefully();
        }
    }
}


客户端handler:

package org.example.protocoltcp;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;

import java.nio.charset.Charset;

public class NettyClientHandler extends SimpleChannelInboundHandler<MessageBean> {


    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        String msg = "==================>AAAA";
        byte[] content = msg.getBytes(Charset.forName("utf-8"));
        int length = content.length;
        MessageBean messageProtocol = new MessageBean();
        messageProtocol.setLen(length);
        messageProtocol.setContent(content);
        ctx.writeAndFlush(messageProtocol);

    }

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

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, MessageBean msg) throws Exception {

    }
}


服务端:

package org.example.protocoltcp;

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;

public class NettyServer {
    public static void main(String[] args) throws Exception {
        EventLoopGroup boosGroup = new NioEventLoopGroup(3);
        EventLoopGroup workerGroup = new NioEventLoopGroup(3);
        try{
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(boosGroup,workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG,128)
                    .childOption(ChannelOption.SO_KEEPALIVE,true)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            socketChannel.pipeline()
                                    .addLast(new MessageBeanEncoder())
                                    .addLast(new MessageBeanDecoder())
                                    .addLast(new NettyServerHandler());
                        }
                    });
         
             ChannelFuture cf = bootstrap.bind(6668).sync();
             cf.channel().closeFuture().sync();

        }finally {
            boosGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}


服务端handler:

package org.example.protocoltcp;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;

public class NettyServerHandler extends SimpleChannelInboundHandler<MessageBean> {

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

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, MessageBean msg) throws Exception {
        byte[] content = msg.getContent();
        System.out.println("============>"+new String(content));

    }
}



参考资源:

 ​ netty权威指南

 ​ 尚硅谷netty视频

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值