Netty之ChannelPipeline(三)Outbound与Inbound事件的传播

  • Outbound事件是请求事件。
  • Outbound事件的发起者是Channel,处理者是Unsafe。
  • Outbound事件在Pipeline中传输方向是tail -> head。

Outbount事件其中之一bind,以bind为例:
AbstractChannel
bind(SocketAddress localAddress, ChannelPromise promise):

@Override
public ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {
    return pipeline.bind(localAddress, promise);
}
  1. 该方法实现自ChannelOutboundInvoker接口。
  2. 方法内部调用被被bind(SocketAddress localAddress, ChannelPromise promise) 方法。

看bind(SocketAddress localAddress, ChannelPromise promise) 方法的具体实现:

@Override
public final ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {
    return tail.bind(localAddress, promise);
}
    @Override
 public ChannelFuture bind(final SocketAddress localAddress, final ChannelPromise promise) {
     if (localAddress == null) {
         throw new NullPointerException("localAddress");
     }
     // 判断 Promise 对象是否合法。
     if (isNotValidPromise(promise, false)) {
         // cancelled
         return promise;
     }
 
     // 获得下一个 Outbound 节点
     final AbstractChannelHandlerContext next = findContextOutbound();
     // 获得下一个 Outbound 节点的执行器
     EventExecutor executor = next.executor();
     // 调用下一个 Outbound 节点的 bind 方法
     if (executor.inEventLoop()) {
         next.invokeBind(localAddress, promise);
     } else {
         safeExecute(executor, new Runnable() {
             @Override
             public void run() {
                 next.invokeBind(localAddress, promise);
             }
         }, promise, null);
     }
     return promise;
 }

上面判断promise对象是否合法,isNotValidPromise(ChannelPromise promise, boolean allowVoidPromise)

private boolean isNotValidPromise(ChannelPromise promise, boolean allowVoidPromise) {
    if (promise == null) {
        throw new NullPointerException("promise");
    }

    // Promise 已经完成
    if (promise.isDone()) {
        // Check if the promise was cancelled and if so signal that the processing of the operation
        // should not be performed.
        //
        // See https://github.com/netty/netty/issues/2349
        if (promise.isCancelled()) {
            return true;
        }
        throw new IllegalArgumentException("promise already done: " + promise);
    }

    // Channel 不符合
    if (promise.channel() != channel()) {
        throw new IllegalArgumentException(String.format(
                "promise.channel does not match: %s (expected: %s)", promise.channel(), channel()));
    }

    // DefaultChannelPromise 合法 
    if (promise.getClass() == DefaultChannelPromise.class) {
        return false;
    }
    // 禁止 VoidChannelPromise 
    if (!allowVoidPromise && promise instanceof VoidChannelPromise) {
        throw new IllegalArgumentException(
                StringUtil.simpleClassName(VoidChannelPromise.class) + " not allowed for this operation");
    }
    // 禁止 CloseFuture
    if (promise instanceof AbstractChannel.CloseFuture) {
        throw new IllegalArgumentException(
                StringUtil.simpleClassName(AbstractChannel.CloseFuture.class) + " not allowed in a pipeline");
    }
    return false;
}

关于调用findContextOutbound()方法,获得下一个Outbound节点:
注意从pipeline的tail->head。

private AbstractChannelHandlerContext findContextOutbound() {
    // 循环,向前获得一个 Outbound 节点
    AbstractChannelHandlerContext ctx = this;
    do {
        ctx = ctx.prev;
    } while (!ctx.outbound);
    return ctx;
}

调用 AbstractChannelHandlerContext#executor() 方法,获得下一个Outbound节点的执行器:
如果未设置子执行器,则Channel的EventLoop作为执行器。

// Will be set to null if no child executor should be used, otherwise it will be set to the
// child executor.

// EventExecutor 对象
 
final EventExecutor executor;

@Override
public EventExecutor executor() {
    if (executor == null) {
        return channel().eventLoop();
    } else {
        return executor;
    }
}
  • 如果在EventLoop的线程中,那么调用下一个节点的invokeBind(SocketAddress localAddress, ChannelPromise promise) 方法,传播 bind 事件给下一个节点。
  • 如果不在EventLoop线程中,调用safeExecute(EventExecutor executor, Runnable runnable, ChannelPromise promise, Object msg)方法,提交到EventLoop的线程中执行:
private static void safeExecute(EventExecutor executor, Runnable runnable, ChannelPromise promise, Object msg) {
    try {
        // 提交到 EventLoop 的线程中,进行执行任务
        executor.execute(runnable);
    } catch (Throwable cause) {
        try {
            // 发生异常,回调通知 promise 相关的异常
            promise.setFailure(cause);
        } finally {
            // 释放 msg 相关的资源
            if (msg != null) {
                ReferenceCountUtil.release(msg);
            }
        }
    }
}

invokeBind(SocketAddress localAddress, ChannelPromise promise) 方法:

 private void invokeBind(SocketAddress localAddress, ChannelPromise promise) {
     if (invokeHandler()) { 
     // 判断是否符合的 ChannelHandler
     // 如果是不符合的ChannelHandler,则跳过该节点。
         try {
             // 调用该 ChannelHandler 的 bind 方法
             ((ChannelOutboundHandler) handler()).bind(this, localAddress, promise);
         } catch (Throwable t) {
             notifyOutboundHandlerException(t, promise); // 通知 Outbound 事件的传播,发生异常
         }
     } else {
         // 跳过,传播 Outbound 事件给下一个节点
         bind(localAddress, promise);
     }
 }

上面调用InvokeHandler()方法,判断是否是符合的ChannelHandler:

/**
 * Makes best possible effort to detect if {@link ChannelHandler#handlerAdded(ChannelHandlerContext)} was called
 * yet. If not return {@code false} and if called or could not detect return {@code true}.
 *
 * If this method returns {@code false} we will not invoke the {@link ChannelHandler} but just forward the event.
 * This is needed as {@link DefaultChannelPipeline} may already put the {@link ChannelHandler} in the linked-list
 * but not called {@link ChannelHandler#handlerAdded(ChannelHandlerContext)}.
 */
private boolean invokeHandler() {
    // Store in local variable to reduce volatile reads.
    int handlerState = this.handlerState;
    return handlerState == ADD_COMPLETE || (!ordered && handlerState == ADD_PENDING);
}

这里。ordered = true的节点,必须与ChannelHandler已添加完毕。
ordered = false的节点,没有ChannelHandler的要求。
bind(ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise) 方法:

@Override
public void bind(ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise) throws Exception {
    unsafe.bind(localAddress, promise);
}

unsafe进行处理。说明Unsafe是bind的处理者。


  • Inbound事件是通知事件。
  • Inbound事件发起者是Unsafe,处理者是TailContext。
  • Inbound事件在Pipeline中传输方向是head -> tail。

Inbound和Outbound很相似,镜像。俺就不说啦。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Netty是一个高性能、异步、事件驱动的网络编程框架。在NettyInbound和Outbound是两个重要的概念,它们分别代表了网络数据的输入和输出。 Inbound是指网络数据从外部进入Netty的过程,也就是数据的输入。当Netty接收到外部的数据,就会调用Inbound的相关方法来处理数据。例如,当Netty接收到一个新的连接请求时,就会调用InboundchannelActive()方法来处理这个连接请求。另外,当Netty接收到一个数据包时,就会调用InboundchannelRead()方法来处理这个数据包。 Outbound是指网络数据从Netty输出到外部的过程,也就是数据的输出。当Netty需要向外部发送数据时,就会调用Outbound的相关方法来处理数据。例如,当Netty需要向外部发送一个数据包时,就会调用Outbound的write()方法来将数据包写入输出缓冲区。另外,当Netty需要关闭一个连接时,就会调用Outbound的close()方法来关闭连接。 总之,Inbound和OutboundNetty非常重要的概念,它们分别代表了网络数据的输入和输出过程。理解它们的作用和使用方法,对于Netty的网络编程非常重要。 ### 回答2: Netty是一个用于构建高性能网络应用程序的开源框架。在NettyInbound和Outbound是两个重要的概念,用于描述数据在网络应用程序的流动方向。 Inbound指的是数据从外部源流入Netty应用程序,也可以理解为数据的输入。在NettyInbound处理器链负责处理接收到的数据,进行解码、处理和转换等操作。它们通常用于处理网络数据协议的解析和应用逻辑的实现。例如,当网络连接建立时,Inbound处理器可以对接收到的数据进行解码,还可以执行身份认证、权限验证等操作。 Outbound指的是数据从Netty应用程序流出到外部目标,也可以理解为数据的输出。在Netty,Outbound处理器链负责处理发送到外部目标的数据,进行编码、处理和转换等操作。它们通常用于处理网络数据协议的编码和发送。例如,在发送数据到网络连接时,Outbound处理器可以对数据进行编码,并处理流控制、拥塞控制等问题,确保数据以可靠、高效的方式发送到目标。 总结起来,Inbound处理器链用于处理从外部源流入Netty应用程序的数据,负责解码、处理和转换等操作;而Outbound处理器链用于处理从Netty应用程序流出到外部目标的数据,负责编码、处理和转换等操作。 理解NettyInbound和Outbound概念对于构建高性能的网络应用程序至关重要。通过合理设计和配置Inbound和Outbound处理器链,可以实现数据的高效传输、协议的解析和发送、以及应用逻辑的实现等功能。这使得Netty成为构建高性能和可扩展的网络应用程序的首选框架之一。 ### 回答3: 在NettyInbound和Outbound是两个重要的概念,它们用于描述网络通信的消息处理流程。理解这两个概念对于使用Netty进行网络编程非常重要。 首先,Inbound(入站)指的是消息从网络到达应用程序的过程,即接收和处理来自客户端或其他网络节点的消息。在NettyInbound的处理流程可以通过实现ChannelInboundHandler接口来实现。通过自定义ChannelInboundHandler,我们可以在接收到消息后进行解码、验证、处理以及生成响应等操作。 其次,Outbound(出站)指的是消息从应用程序发送到网络的过程,即将应用程序的响应发送给客户端或其他网络节点。在Netty,Outbound的处理流程可以通过实现ChannelOutboundHandler接口来实现。通过自定义ChannelOutboundHandler,我们可以在发送消息之前进行编码、加密、压缩等操作,以及在发送消息之后进行清理等操作。 通过Inbound和Outbound的结合使用,我们可以有效地处理消息的收发。比如,当接收到Inbound消息后,我们可以在Inbound处理链对消息进行解码,并将解码后的消息转发给Outbound处理链的下一个节点进行处理或发送;而在Outbound处理链,我们可以对消息进行编码,并将其发送到网络。 此外,通过Netty提供的ChannelInitializer,我们可以对Inbound和Outbound处理链进行组合和配置,实现一个完整的消息处理流程。在这个流程,每个Inbound处理器都可以处理来自网络的入站消息,每个Outbound处理器都可以处理应用程序的出站消息。 总之,Inbound和OutboundNetty用来描述消息处理流程的重要概念。理解它们的作用和用法,可以帮助我们更好地使用Netty进行网络编程,实现可靠的消息通信。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值