Netty源码分析(一):客户端操作之channel()

  • 注:以im系统为基础开始分析,源码会截取最重要的一部分,而不是全部,以观全貌
  • 代码可参考:简易版im聊天系统

1.首先回顾一下同步、异步、阻塞、非阻塞:

同步异步是相对于IO而言的,在同一时间,只能完成一个操作,则为同步(NIO);能同时完成多个操作,则为异步(AIO)。

阻塞非阻塞是相对于数据而言的,判断数据有没有准备好,如果数据没有准备好,则一直等待,则为阻塞(BIO);如果不管数据有没有准备好,都会给一个反馈,客户端可以去做一些其他事情,则为非阻塞。

简单来说,同步异步针对于底层操作系统的IO操作,阻塞非阻塞针对于接口的调用

而Netty是基于NIO的异步非阻塞,异步的原因是加了一个线程池,在同一时间,就能同时完成多个操作,拥有了异步响应;
异步响应是从Handler来体现的,这些Handler组成了Pipeline,即一条无锁化串行的链路

2.开始源码分析

2.1 Bootstrap

其使用链为

EventLoopGroup workerGroup = new NioEventLoopGroup();
Bootstrap bootstrap = new Bootstrap();
bootstrap .group(workerGroup);
		  .channel(NioSocketChannel.class);
		  .option(ChannelOption.SO_KEEPALIVE, true);
		  .handler(new ChannelInitializer<SocketChannel>() {
   		      。。。
		  });
ChannelFuture f = b.connect(this.host, this.port).sync();
f.channel().closeFuture().sync();

客户端:Bootstrap;服务端:ServerBootstrap

2.1.1 客户端Bootstrap

2.1.1.1 channel方法:将不同类型的Channel类型放入管道中

首先分析一下Channel的初始化过程:

ChannelFactory负责初始化实现了Channel接口的类,不同协议、不同阻塞类型的连接都有不同的Channel类型与之对应,下图是一些常用的Channel类型:
在这里插入图片描述
因为是讲客户端,所以这里看一下NioSocketChannel,其类层次结构图如下:
在这里插入图片描述
注意到,NioSocketChannel是Nio客户端的起始类
这里以NioSocketChannel为例,来查看源码:

AbstractBootstrap#
public B channel(Class<? extends C> channelClass) {
    return channelFactory(new ReflectiveChannelFactory<C>(channelClass));*
}
ReflectiveChannelFactory#
public ReflectiveChannelFactory(Class<? extends T> clazz) {
    this.clazz = clazz;
}
public T newChannel() {
    return clazz.newInstance();
}

可以看到,这里初始化了ReflectiveChannelFactory,而ReflectiveChannelFactory实现了ChannelFactory接口,将class保存下来,进行newInstance。即将new的权利交给了框架,类似IOC

那么什么时候调用newChannel呢?调用链如下:

final ChannelFuture initAndRegister() {
    channel = channelFactory.newChannel();
}

因此可以看到,connect是实例化channel必备的代码

使用class的newInstance,会调用类的构造方法,即NioSocketChannel的默认构造方法:

public NioSocketChannel() {
    //DEFAULT_SELECTOR_PROVIDER为Nio的provider,= SelectorProvider.provider()
    //即不同操作系统的IO多路复用器:https://www.jianshu.com/p/3cf951d46c35
    this(DEFAULT_SELECTOR_PROVIDER);
}
public NioSocketChannel(SelectorProvider provider) {
    this(newSocket(provider));//return provider.openSocketChannel();即获取SocketChannel
}
public NioSocketChannel(SocketChannel socket) {
    this(null, socket);
}
public NioSocketChannel(Channel parent, SocketChannel socket) {
    super(parent, socket);//ch.configureBlocking(false);
    config = new NioSocketChannelConfig(this, socket.socket());
}
protected AbstractChannel(Channel parent) {
    this.parent = parent;
    id = newId();
    unsafe = newUnsafe();//模板模式,由子类实现
    pipeline = newChannelPipeline();//new DefaultChannelPipeline(this);
}
  • 总结:NioSocketChannel的实例化,本质就是SocketChannel的实例化,且可以看到的是:
    super(parent, socket);中的AbstractNioChannel构造方法设置了非阻塞模式,也设置为了SelectionKey.OP_READ,等待读取;
    继续super到AbstractChannel构造方法,可以看到其实例化了pipeline字段(DefaultChannelPipeline)、unsafe字段(AbstractNioByteChannel的内部类NioByteUnsafe,直接new NioByteUnsafe();就结束了)

下面可以来看看组合进Channel的pipeline和unsafe:

1.pipeline:实例化Channel过程中,也实例化了ChannelPipeline

protected DefaultChannelPipeline(Channel channel) {
    this.channel = ObjectUtil.checkNotNull(channel, "channel");
    succeededFuture = new SucceededChannelFuture(channel, null);
    voidPromise =  new VoidChannelPromise(channel, true);

    tail = new TailContext(this);
    head = new HeadContext(this);
	//头尾相连,next和prev由volatile修饰
    head.next = tail;
    tail.prev = head;
}

可以看到,其本质就是一个链表,体现了能够进行串行化的原因
接下来看看孪生兄弟HeadContext和TailContext:

final class HeadContext extends AbstractChannelHandlerContext
implements ChannelOutboundHandler, ChannelInboundHandler{
	//即令inbound = false;outbound = true;
	super(pipeline, null, HEAD_NAME, false, true);
}
final class TailContext extends AbstractChannelHandlerContext 
implements ChannelInboundHandler{
	//即令inbound = true;outbound = false;
	super(pipeline, null, TAIL_NAME, true, false);
}

所以header是一个outboundHandler,tail是一个inboundHandler,header比tail多实现了一个ChannelOutboundHandler接口

2.unsafe:封装了对Java底层Socket的操作,是沟通Netty上层和Java底层重要的桥梁

protected class NioByteUnsafe extends AbstractNioUnsafe {}
protected abstract class AbstractNioUnsafe extends AbstractUnsafe implements NioUnsafe{}
public interface NioUnsafe extends Unsafe{}
interface Unsafe{}

可以看到,最深层的接口为Unsafe:

interface Unsafe {
    RecvByteBufAllocator.Handle recvBufAllocHandle();
    SocketAddress localAddress();
    SocketAddress remoteAddress();
    void register(EventLoop eventLoop, ChannelPromise promise);
    void bind(SocketAddress localAddress, ChannelPromise promise);
    void connect(SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise);
    void disconnect(ChannelPromise promise);
    void close(ChannelPromise promise);
    void closeForcibly();
    void deregister(ChannelPromise promise);
    void beginRead();
    void write(Object msg, ChannelPromise promise);
    void flush();
    ChannelPromise voidPromise();
    ChannelOutboundBuffer outboundBuffer();
}

可以看到,无非是一些注册、绑定、关闭、连接、半开连接之类的底层操作,这些方法都会有相关的Java底层的Socket操作

channel初始化之后,来分析一下channel的注册:

回顾刚才的initAndRegister方法,里面调用了init(channel):

void init(Channel channel) throws Exception {
    ChannelPipeline p = channel.pipeline();
    p.addLast(config.handler());
}

可以看到在pipeline中加入了一个config.handler,这个handler实际上就是在使用代码中的ChannelInitializer,ChannelInitializer,它有一个抽象方法initChannnel方法,用来addLast

接下来继续看调用,其调用链为:

AbstractChannel$AbstractUnsafe#register()

public final void register(EventLoop eventLoop, final ChannelPromise promise) {
    AbstractChannel.this.eventLoop = eventLoop;
    register0(promise);
}

register0:

protected void doRegister() throws Exception {
    selectionKey = javaChannel().register(eventLoop().selector, 0, this);
}

可以看到,往Selector中注册一个事件,这个事件就是上面所说的OP_READ;然后返回一个Nio的SocketChannel,这个SocketChannel是已经注册到与eventLoop关联的selector上了

Channe注册过程总结:就是将Channel与对应的EventLoop关联,填充EventLoopGroup
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_41594698/article/details/89738304