Netty 源码调试

本文详细介绍了Netty源码调试的过程,从环境搭建到源码分析,涵盖了Netty启动入口、initAndRegister()方法的各个步骤,包括newChannel()、init(channel)和register(channel)。文章剖析了Channel、EventLoopGroup、ServerBootstrap等核心组件,解析了NioServerSocketChannel的构造过程和事件循环Group的工作原理,强调了ChannelPipeline在处理网络事件中的作用。
摘要由CSDN通过智能技术生成

Netty 源码调试

一、环境搭建

<dependency>
    <groupId>io.netty</groupId>
    <artifactId>netty-all</artifactId>
    <version>4.1.68.Final</version>
</dependency>
public class NettyServer {
   

    public static void main(String[] args) throws Exception{
   

        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        ServerBootstrap bootstrap = new ServerBootstrap();

        bootstrap.group(bossGroup, 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 NettyServerHandler());
                    }
                });    //设置处理器
        System.out.println("服务器 is ready。。。。。");
        ChannelFuture channelFuture = bootstrap.bind(6668).sync();

        //对关闭通道进行监听
        channelFuture.channel().closeFuture().sync();

    }

}
public class NettyServerHandler extends ChannelInboundHandlerAdapter {
   

    //读取客户端对消息
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
   

        System.out.println("server ctx "+ ctx);
        ByteBuf buf = (ByteBuf) msg;
        System.out.println("客户端发生消息是:"+buf.toString(StandardCharsets.UTF_8));
        System.out.println("客户端地址:"+ctx.channel().remoteAddress());

    }

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

        ctx.channel().eventLoop().execute(new Runnable() {
   
            @Override
            public void run() {
   
                try {
   
                    Thread.sleep(5000);
                    ctx.writeAndFlush(Unpooled.copiedBuffer("hello 客户端..2",StandardCharsets.UTF_8));
                }catch (Exception e){
   

                }
            }
        });

        ctx.channel().eventLoop().execute(new Runnable() {
   
            @Override
            public void run() {
   
                try {
   
                    Thread.sleep(5000);
                    ctx.writeAndFlush(Unpooled.copiedBuffer("hello 客户端..3",StandardCharsets.UTF_8));
                }catch (Exception e){
   

                }
            }
        });


        Thread.sleep(5000);

        ctx.writeAndFlush(Unpooled.copiedBuffer("hello 客户端..1",StandardCharsets.UTF_8));
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
   
        System.out.println("channelActive");
    }

    //发生异常 关闭通道
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
   
        ctx.channel().close();
    }
}

二、开始调试

1、netty启动入口

首先是这一行代码–>ChannelFuture channelFuture = bootstrap.bind(6668).sync();

点进bind方法之后

public ChannelFuture bind(int inetPort) {
   
  	//将port封装成一个对象
    return this.bind(new InetSocketAddress(inetPort));
}

继续往下点

public ChannelFuture bind(SocketAddress localAddress) {
   
  	//从方法名上剋看出 是先校验 之后再执行doBind方法,有spring方法起名的味道了
    this.validate();
    return this.doBind((SocketAddress)ObjectUtil.checkNotNull(localAddress, "localAddress"));
}

点进去doBind方法 我们看到一堆代码。。。。

private ChannelFuture doBind(final SocketAddress localAddress) {
   
  
    final ChannelFuture regFuture = this.initAndRegister();
    final Channel channel = regFuture.channel();
    if (regFuture.cause() != null) {
   
        return regFuture;
    } else if (regFuture.isDone()) {
   
      
        ChannelPromise promise = channel.newPromise();
        doBind0(regFuture, channel, localAddress, promise);
        return promise;
    } else {
   
        final AbstractBootstrap.PendingRegistrationPromise promise = new AbstractBootstrap.PendingRegistrationPromise(channel);
        regFuture.addListener(new ChannelFutureListener() {
   
            public void operationComplete(ChannelFuture future) throws Exception {
   
                Throwable cause = future.cause();
                if (cause != null) {
   
                    promise.setFailure(cause);
                } else {
   
                    promise.registered();
                    AbstractBootstrap.doBind0(regFuture, channel, localAddress, promise);
                }

            }
        });
        return promise;
    }
}

但是核心操作只有两步

//第一步 初始化并注册
final ChannelFuture regFuture = this.initAndRegister();
//第二部进行绑定
doBind0(regFuture, channel, localAddress, promise);

接下来 我们就要主要探究这两个步骤!!

2、initAndRegister()

final ChannelFuture initAndRegister() {
   
    Channel channel = null;

    try {
   
        channel = this.channelFactory.newChannel();
        this.init(channel);
    } catch (Throwable var3) {
   
        if (channel != null) {
   
            channel.unsafe().closeForcibly();
            return (new DefaultChannelPromise(channel, GlobalEventExecutor.INSTANCE)).setFailure(var3);
        }

        return (new DefaultChannelPromise(new FailedChannel(), GlobalEventExecutor.INSTANCE)).setFailure(var3);
    }

    ChannelFuture regFuture = this.config().group().register(channel);
    if (regFuture.cause() != null) {
   
        if (channel.isRegistered()) {
   
            channel.close();
        } else {
   
            channel.unsafe().closeForcibly();
        }
    }

    return regFuture;
}

我们接着看他的关键步骤:

1、newChannel() ; 创建一个channel

2、this.init(channel); 初始化这个channel

3、this.config().group().register(channel); 注册这个channel

我们再一个一个点方法探究!!!

newChannel()
@Deprecated
public interface ChannelFactory<T extends Channel> {
   
    T newChannel();
}

我们看到这是个接口,我们就要向下找他的实现类 最终我们找到了ReflectiveChannelFactory

public class ReflectiveChannelFactory<T extends Channel> implements ChannelFactory<T> {
   
    private final Constructor<? extends T> constructor;

    public ReflectiveChannelFactory(Class<? extends T> clazz) {
   
        ObjectUtil.checkNotNull(clazz, "clazz");

        try {
   
            this.constructor = clazz.getConstructor();
        } catch (NoSuchMethodException var3) {
   
            throw new IllegalArgumentException("Class " + StringUtil.simpleClassName(clazz) + " does not have a public non-arg constructor", var3);
        }
    }

    public T newChannel() {
   
        try {
   
            return (Channel)this.constructor.newInstance();
        } catch (Throwable var2) {
   
            throw new ChannelException("Unable to create Channel from class " + this.constructor.getDeclaringClass(), var2);
        }
    }

    public String toString() {
   
        return StringUtil.simpleClassName(ReflectiveChannelFactory.class) + '(' + StringUtil.simpleClassName(this.constructor.getDeclaringClass()) + ".class)";
    }
}

我们看看这个类的代码,非常简单,主要就ReflectiveChannelFactory(args)方法 去获得一个constructor

让我们再返回到我们的小dome中**bootstrap.channel(NioServerSocketChannel.class)我们这一步就是通过反射来创建当时我们设置的Channel类型,具体创建是newChannel()**方法

绕了一圈 其实我们 newChannel()方法就是给我们创建一个我们指定的channel


好了 接下来让我们看看我们指定点NioServerSocketChannel到底是个什么东西,这个类真的很重要!

我们先看一下他的构造器

private static java.nio.channels.ServerSocketChannel newSocket(SelectorProvider provider) {
   
    try {
   
        return provider.openServerSocketChannel();
    } catch (IOException var2) {
   
        throw new ChannelException("Failed to open a server socket.", var2);
    }
}

public NioServerSocketChannel() {
   
    this(newSocket(DEFAULT_SELECTOR_PROVIDER));
}

public NioServerSocketChannel(SelectorProvider provider) {
   
    this(newSocket(provider));
}

public NioServerSocketChannel(java.nio.channels.ServerSocketChannel channel) {
   
    super((Channel)null, channel, 16);
    this.config = new NioServerSocketChannel.NioServerSocketChannelConfig(this, this.javaChannel().socket());
}

他的构造器最终都走回了这个方法

public NioServerSocketChannel(java.nio.channels.ServerSocketChannel channel) {
   
  	//调用上层方法
    super((Channel)null, channel, 16);
  	//创建config
    this.config = new NioServerSocketChannel.NioServerSocketChannelConfig(this, this.javaChannel().socket());
}

这个config是我们Netty的一个核心我们要记住他是在Channel初始化的时候就创建了

我们的super一直向上点,会点到AbstractNioChannel这个抽象类,注意看注解!

protected AbstractNioChannel(Channel parent, SelectableChannel ch, int readInterestOp) {
   
    
  	//又向上调用父类的构造方法 并且这个parent是之前设置的null
  	super(parent);
  
  	//设置channel
    this.ch = ch;
  	//设置之前传点那个16 其实就是状态设置为SelectionKey.OP_ACCEPT
    this.readInterestOp = readInterestOp;

    try {
   
      	//这里很像我们jdk nio点时候设置成非阻塞模式
        ch.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值