netty踩坑--Unpooled.copiedBuffer(ByteBuffer buffer)

netty踩坑Unpooled.copiedBuffer(ByteBuffer buffer)

    • 一、BUG评级
    • 二、概述
    • 三、Code review
    • 四、BUG分析
    • 五、完整代码
    • 六、其他博主的详细介绍

一、BUG评级

  1. BUG发现难度:★☆☆☆☆
  2. BUG无法复现概率:☆☆☆☆☆
  3. BUG偶然引入概率:★★☆☆☆
  4. BUG修复,烧脑程度:★★☆☆☆ (随手优化了下代码就不行了T_T)

二、概述

起一个netty服务端,起一个硬件设备,相互通信。
在优化了一堆代码后,发现收不到报文
(这里模拟客户端无法向服务器发送报文)

三、Code review

 Channel channel = future.channel();
while (true) {
    ByteBuffer finalByteBuffer = ByteBuffer.allocate(2);
    finalByteBuffer.put((byte) 66);
    finalByteBuffer.put((byte) 88);

    // 用下面这个发不出去
    ByteBuf byteBuf = Unpooled.copiedBuffer(finalByteBuffer);
    // 用下面这2个可以发出去
//  ByteBuf byteBuf = Unpooled.copiedBuffer((ByteBuffer) finalByteBuffer.position(0));
//  ByteBuf byteBuf = Unpooled.copiedBuffer(finalByteBuffer.array());

    channel.writeAndFlush(byteBuf);
    TimeUnit.SECONDS.sleep(2);
}

四、BUG分析

来看下这个重载方法的源码
netty踩坑--Unpooled.copiedBuffer(ByteBuffer buffer)_第1张图片debug发现,代码进入了

if (length == 0) {
  return EMPTY_BUFFER;
}

也就是说后续的代码发了个空气~~

回到上面那个方法,

int length = buffer.remaining();  <----看这里
if (length == 0) {
    return EMPTY_BUFFER;
}

查看buffer.remaining()的实现
netty踩坑--Unpooled.copiedBuffer(ByteBuffer buffer)_第2张图片意思很清楚,返回positon指针到尾部之间的数据,因为上面的put操作移动了position指针,所以返回了EMPTY_BUFFER

五、完整代码

git链接:https://gitee.com/testnewbie-projects/testnewbie-training-camp/blob/master/code-snippet/src/main/java/cn/testnewbie/training/camp/bug03/CopiedBufferMethod.java

源代码:(需要引入netty包)

package cn.testnewbie.training.camp.bug03;

import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.bytes.ByteArrayDecoder;
import io.netty.handler.codec.bytes.ByteArrayEncoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.concurrent.TimeUnit;

public class CopiedBufferMethod {

    public static void main(String[] args) throws IOException {
        new ServerThread().start();
        new ClientThread().start();

        System.in.read();
    }

    static class ServerThread extends Thread {
        NioEventLoopGroup boss = new NioEventLoopGroup(1);
        NioEventLoopGroup worker = new NioEventLoopGroup(1);

        @Override
        public void run() {
            ServerBootstrap boot = new ServerBootstrap();

            try {
                boot.group(boss, worker)
                        .channel(NioServerSocketChannel.class)
                        .option(ChannelOption.TCP_NODELAY, false)
                        .childHandler(new ChannelInitializer<NioSocketChannel>() {
                            @Override
                            protected void initChannel(NioSocketChannel ch) {
                                ch.pipeline()
                                        .addLast(new ByteArrayDecoder())
                                        .addLast(new ByteArrayEncoder())
                                        .addLast(new ServerHandler());
                            }
                        })
                        .bind(9999)
                        .sync()             //阻塞当前线程到服务启动起来
                        .channel()
                        .closeFuture()
                        .sync();            //阻塞当前线程到服务停止


            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    static class ClientThread extends Thread {
        NioEventLoopGroup group = new NioEventLoopGroup(1);

        @Override
        public void run() {
            Bootstrap bootstrap = new Bootstrap();

            bootstrap.group(group)
                    .channel(NioSocketChannel.class)
                    .handler(new ChannelInitializer<NioSocketChannel>() {
                        @Override
                        protected void initChannel(NioSocketChannel ch) {
                            ch.pipeline()
                                    .addLast(new ByteArrayDecoder())
                                    .addLast(new ByteArrayEncoder());
                        }
                    });
            ChannelFuture f = bootstrap.connect("localhost", 9999);
            // 连接状态可以动listener中获取到
            f.addListener(new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture future) throws Exception {
                    if (!future.isSuccess()) {
                        System.out.println("not connected!");
                    } else {
                        Channel channel = future.channel();
                        while (true) {
                            ByteBuffer finalByteBuffer = ByteBuffer.allocate(2);
                            // put的时候,ByteBuffer的position指针会移动
                            // 导致Unpooled.copiedBuffer(ByteBuffer buffer)返回了EMPTY_BUFFER
                            finalByteBuffer.put((byte) 66);
                            finalByteBuffer.put((byte) 88);

                            // 用下面这个发不出去
                            ByteBuf byteBuf = Unpooled.copiedBuffer(finalByteBuffer);
                            // 用下面这2个可以发出去
                            //  ByteBuf byteBuf = Unpooled.copiedBuffer((ByteBuffer) finalByteBuffer.position(0));
                            //  ByteBuf byteBuf = Unpooled.copiedBuffer(finalByteBuffer.array());

                            channel.writeAndFlush(byteBuf);
                            TimeUnit.SECONDS.sleep(2);
                        }
                    }
                }
            });

        }
    }

    static class ServerHandler extends ChannelInboundHandlerAdapter {
        private static Logger logger = LoggerFactory.getLogger(ServerHandler.class);

        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) {
            logger.info("channelRead msg = {}", msg);
        }

    }
}

六、其他博主的详细介绍

https://blog.csdn.net/shuaiAWP/article/details/51915983

你可能感兴趣的:(技术,netty,socket)