Netty in Android application development in actual combat series (four) --- stick package | unpacking process

Read the article suggests looking back from the beginning of the first chapter

This series of articles

First, what does stick package?

Is simply: transmitting a plurality of packets to an adherend into a package.
For example: the server sends two consecutive packets clients really only received a package (which is actually a package of two data packets), normal for the client should receive two packages. This is called the client stick package in which case you need to do the unpacking process.

Second, the general processing means of the stick package

  • Use fixed-length
  • Use special character segmentation ($, \ n ...)
  • other

Netty also provides us several processing decoder stick package, as follows:

  • DelimiterBasedFrameDecoder For stick package unpacking processing on the basis of special characters
  • FixedLengthFrameDecoder Unpacking processing performed based on a fixed stick package length
  • LengthFieldBasedFrameDecoder Specifies the message length stick package unpacking process based on message header
  • LineBasedFrameDecoder For stick package unpacking processing based on line breaks (\ r \ n, \ n)

Third, by the following examples to handle a stick package unpacking, where I use DelimiterBasedFrameDecoderthe decoder is then used $as a special delimiter

First, add 3.1 to the serverDelimiterBasedFrameDecoder

/**
 * 启动tcp服务端
 */
public void startServer() {
    try {
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        ServerBootstrap b = new ServerBootstrap();
        b.group(bossGroup, workerGroup)
                .channel(NioServerSocketChannel.class)
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    //分隔符
                    ByteBuf delimiter = Unpooled.copiedBuffer("$".getBytes());
                    @Override
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        ChannelPipeline pipeline = socketChannel.pipeline();
                        //解决粘包
                        pipeline.addLast(new DelimiterBasedFrameDecoder(65535, delimiter));
                        //添加发送数据编码器
                        pipeline.addLast(new ServerEncoder());
                        //添加解码器,对收到的数据进行解码
                        pipeline.addLast(new ServerDecoder());
                        //添加数据处理
                        pipeline.addLast(new ServerHandler());
                    }
                });
        //服务器启动辅助类配置完成后,调用 bind 方法绑定监听端口,调用 sync 方法同步等待绑定操作完成
        b.bind(PORT).sync();
        handler.obtainMessage(0, "TCP 服务启动成功 PORT = " + PORT).sendToTarget();
        Log.d(TAG, "TCP 服务启动成功 PORT = " + PORT);
    } catch (Exception e) {
        e.printStackTrace();
    }

3.2 Since the use of special separators stick package for handling, then the need to transmit each data packet is added on the $symbol; defined only need Encoderto add to, the following:

public class ServerEncoder extends MessageToByteEncoder<PkgDataBean> {

    private static final String TAG = "ServerEncoder";

    @Override
    protected void encode(ChannelHandlerContext channelHandlerContext, PkgDataBean data, ByteBuf byteBuf) throws Exception {
        //根据数据包协议,生成byte数组
        byte[] bytes = {0x2A, data.getCmd(), data.getDataLength()};
        byte[] dataBytes = data.getData().getBytes();
        //分隔符
        byte[] delimiter = "$".getBytes();
        //将所有数据合并成一个byte数组
        byte[] all = ByteUtil.byteMergerAll(bytes, dataBytes, new byte[]{0x2A}, delimiter);
        //发送数据
        byteBuf.writeBytes(all);
    }
}

3.3 We write code consecutive transmit packets

//获取与客户端的连接
List<ChannelHandlerContext> channels = ServerHandler.channels;
for (ChannelHandlerContext ctx : channels) {
    for (int i = 0; i < 3; i++) {
        PkgDataBean bean = new PkgDataBean();
        bean.setCmd((byte) 0x05);
        bean.setData("粘包的数据:" + i);
        bean.setDataLength((byte) bean.getData().getBytes().length);
        ctx.channel().writeAndFlush(bean);
    }
}
Log.d(TAG, "服务端发送了粘包数据");

Fourth, since the server has been added to the DelimiterBasedFrameDecoderdecoder, then the client also needs to add synchronization; otherwise it is impossible to resolve the abnormal data

public void connect() {
    try {
        NioEventLoopGroup group = new NioEventLoopGroup();
        Bootstrap bootstrap = new Bootstrap()
                // 指定channel类型
                .channel(NioSocketChannel.class)
                // 指定EventLoopGroup
                .group(group)
                // 指定Handler
                .handler(new ChannelInitializer<SocketChannel>() {
                    //分隔符
                    ByteBuf delimiter = Unpooled.copiedBuffer("$".getBytes());
                    @Override
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        ChannelPipeline pipeline = socketChannel.pipeline();
                        pipeline.addLast(new IdleStateHandler(10, 0, 0));
                        //解决粘包
                        pipeline.addLast(new DelimiterBasedFrameDecoder(65535, delimiter));
                        //添加发送数据编码器
                        pipeline.addLast(new ClientEncoder());
                        //添加收到的数据解码器
                        pipeline.addLast(new ClientDecoder());
                        //添加数据处理器
                        pipeline.addLast(new ClientHandler(NettyClient.this));
                    }
                });
        // 连接到服务端
        ChannelFuture channelFuture = bootstrap.connect(new InetSocketAddress(IP, PORT));
        // 添加连接状态监听
        channelFuture.addListener(new ConnectListener(this));
        //获取连接通道
        channel = channelFuture.sync().channel();
        handler.obtainMessage(0, "连接成功").sendToTarget();
    } catch (Exception e) {
        handler.obtainMessage(0, "连接失败").sendToTarget();
        Log.e(TAG, "连接失败:" + e.getMessage());
        e.printStackTrace();
    }
}
  • Similarly, data sent by the client will write the end of the packet $symbols.

Fifth, now look at the effect of program execution

  • The server transmits three consecutive data
    Here Insert Picture Description
  • Data received by the client
    Here Insert Picture Description

For other unpacking decoder you can pick a suitable use according to their actual situation, to the basic application here in Android Netty whole would talk about it; I believe you read this four blog can also be used in actual combat Netty duck to water

This series of articles Demo Download

Welcome to exchange QQ group together
Here Insert Picture Description

Published 140 original articles · won praise 546 · views 540 000 +

Guess you like

Origin blog.csdn.net/a_zhon/article/details/101039462
Recommended