Netty中AbstractChannelHandlerContext源码分析

Netty源码分析:ChannelPipeline Netty源码分析:ChannelPipeline在博文Netty源码分析:服务端启动全过程我们在知道NioServerSocketChannel这个类的构造函数的调用链如下: public NioServerSocketChannel() { this(newSocket(DEFAULT_SELECTOR_PROVIDER));//newSocket的功能为:利用Select 阅读详情

io.netty.channel.AbstractChannelHandlerContext 是 Netty 框架中 ChannelHandlerContext 接口的抽象实现,充当 ChannelHandler 与 ChannelPipeline 之间的桥梁。它是 Netty 事件驱动模型的核心组件,负责事件传播、上下文管理和管道操作。本文将详细解析 AbstractChannelHandlerContext 的源码,添加注释解释关键逻辑,分析其设计、功能和使用场景,结合 HTTP 协议等示例说明如何使用。


1. AbstractChannelHandlerContext 概述

1.1 定义

AbstractChannelHandlerContext 是 ChannelHandlerContext 的抽象实现,位于 io.netty.channel 包中。它实现了 ChannelHandlerContext、ChannelInboundInvoker 和 ChannelOutboundInvoker 接口,提供事件传播、上下文访问和管道操作的核心功能。

  • 源码位置:transport/src/main/java/io/netty/channel/AbstractChannelHandlerContext.java

  • 继承关系:

    java.lang.Object
    
    └── io.netty.util.DefaultAttributeMap
    
        └── io.netty.channel.AbstractChannelHandlerContext (abstract class)
    
            └── io.netty.channel.DefaultChannelHandlerContext (final class)
    
    • 实现接口:ChannelHandlerContext、ChannelInboundInvoker、ChannelOutboundInvoker、ResourceLeakHint。
    • 继承 DefaultAttributeMap,提供属性管理功能。
  • 主要功能:

    • 事件传播:支持入站(如 fireChannelRead)和出站(如 write)事件的传播。
    • 上下文管理:提供对 Channel、ChannelPipeline、ChannelHandler 和 EventExecutor 的访问。
    • 管道操作:支持动态添加/移除 ChannelHandler。
    • 线程安全:确保事件处理在 EventLoop 线程中执行。

1.2 设计理念

  • 事件驱动:基于 Netty 的管道模型,事件在 ChannelHandlerContext 链中传播。
  • 解耦:将 ChannelHandler 的逻辑与管道和通道解耦,通过上下文访问资源。
  • 灵活性:支持动态修改管道,适应协议切换(如 HTTP 到 WebSocket)。
  • 性能优化:使用双向链表和单线程模型,减少锁竞争。

2. 源码解析

以下对 AbstractChannelHandlerContext 的源码进行详细分析,添加注释解释关键字段和方法。源码基于 Netty 4.1 。

2.1 关键字段

abstract class AbstractChannelHandlerContext implements ChannelHandlerContext, ResourceLeakHint {

    // 双向链表,指向下一个和上一个上下文

    volatile AbstractChannelHandlerContext next;

    volatile AbstractChannelHandlerContext prev;



    // 关联的 ChannelPipeline

    private final DefaultChannelPipeline pipeline;



    // 上下文的唯一名称

    private final String name;



    // 标记是否支持入站/出站事件

    private final boolean inbound;

    private final boolean outbound;



    // 关联的 EventExecutor(通常是 EventLoop)

    private final EventExecutor executor;



    // 绑定的 ChannelHandler

    private final ChannelHandler handler;



    // 上下文状态(INIT, ADD_PENDING, ADD_COMPLETE, REMOVE_COMPLETE)

    private volatile int handlerState = INIT;



    // 事件掩码,标记支持的事件类型

    private final int executionMask;



    // 属性存储,用于通道相关的键值对

    private final DefaultAttributeMap attributes = new DefaultAttributeMap();



    // 跳过标志,用于优化事件传播

    private volatile boolean skipContext;



    // 管道操作的 Promise

    private ChannelPromise voidPromise;



    // 资源泄漏检测

    private final ResourceLeakTracker<?> leak;

}
  • 字段分析:
    • next 和 prev:实现双向链表,连接管道中的上下文,事件沿链表传播。
    • pipeline:关联的 ChannelPipeline,提供管道操作接口。
    • name:上下文的唯一标识,用于定位 ChannelHandler。
    • inbound 和 outbound:标记 ChannelHandler 是否为 ChannelInboundHandler 或 ChannelOutboundHandler。
    • executor:事件处理线程,通常是 NioEventLoop。
    • handler:绑定的 ChannelHandler,负责事件处理逻辑。
    • handlerState:管理上下文生命周期(添加、移除等)。
    • executionMask:位掩码,优化事件传播,标记支持的事件类型。
    • attributes:存储通道相关的键值对(如用户数据)。
    • leak:资源泄漏检测,追踪 ByteBuf 等资源。

2.2 关键方法

2.2.1 构造函数
AbstractChannelHandlerContext(DefaultChannelPipeline pipeline, EventExecutor executor,

                             String name, Class<? extends ChannelHandler> handlerClass) {

    this.name = ObjectUtil.checkNotNull(name, "name");

    this.pipeline = pipeline;

    this.executor = executor;

    this.handler = ObjectUtil.checkNotNull(handlerClass, "handlerClass").cast(null);

    this.inbound = ChannelInboundHandler.class.isAssignableFrom(handlerClass);

    this.outbound = ChannelOutboundHandler.class.isAssignableFrom(handlerClass);

    this.executionMask = calculateExecutionMask(handlerClass);

    this.leak = leakDetection() ? pipeline.leakDetector().track(this) : null;

}
  • 注释:
    • name:上下文名称,确保唯一性。
    • pipeline:关联的管道实例。
    • executor:事件执行器,通常是 EventLoop。
    • handlerClass:ChannelHandler 的类,用于判断 inbound 和 outbound。
    • executionMask:根据 handlerClass 计算支持的事件。
    • leak:启用资源泄漏检测。
2.2.2 入站事件传播(fireChannelRead)
@Override

public ChannelHandlerContext fireChannelRead(final Object msg) {

    // 查找下一个支持 channelRead 事件的上下文

    invokeChannelRead(findContextInbound(MASK_CHANNEL_READ), msg);

    return this;

}



static void invokeChannelRead(final AbstractChannelHandlerContext next, Object msg) {

    // 检查消息非空并记录资源引用

    final Object m = next.pipeline().touch(ObjectUtil.checkNotNull(msg, "msg"), next);

    EventExecutor executor = next.executor();

    // 如果在 EventLoop 线程中,直接调用

    if (executor.inEventLoop()) {

        next.invokeChannelRead(m);

    } else {

        // 提交到 EventLoop 线程

        executor.execute(() -> next.invokeChannelRead(m));

    }

}



private void invokeChannelRead(Object msg) {

    // 检查 handler 是否可用

    if (invokeHandler()) {

        try {

            // 调用 ChannelInboundHandler 的 channelRead 方法

            ((ChannelInboundHandler) handler()).channelRead(this, msg);

        } catch (Throwable t) {

            // 捕获异常并传播

            notifyHandlerException(t);

        }

    } else {

        // 跳过当前上下文,继续传播

        fireChannelRead(msg);

    }

}
  • 分析:
    • fireChannelRead:触发入站事件,传播到下一个支持 channelRead 的上下文。
    • invokeChannelRead:
      • 使用 pipeline().touch 跟踪资源(如 ByteBuf)。
      • 检查 inEventLoop 确保线程安全。
      • 如果不在 EventLoop,提交任务。
    • invokeHandler:检查 handlerState 确保 ChannelHandler 未被移除。
    • 异常处理:捕获 channelRead 异常,调用 fireExceptionCaught。
2.2.3 出站事件传播(write)
@Override

public ChannelFuture write(Object msg) {

    return write(msg, newPromise());

}



@Override

public ChannelFuture write(final Object msg, final ChannelPromise promise) {

    write(msg, false, promise);

    return promise;

}



private void write(Object msg, boolean flush, ChannelPromise promise) {

    // 查找下一个支持 write 或 flush 事件的上下文

    AbstractChannelHandlerContext next = findContextOutbound(flush ? MASK_WRITE | MASK_FLUSH : MASK_WRITE);

    ReferenceCountUtil.touch(msg, this);

    if (next == null) {

        // 没有出站处理器,设置失败

        safeExecute(executor(), () -> promise.setFailure(new IllegalStateException("no outbound handler")), promise);

    } else {

        EventExecutor executor = next.executor();

        if (executor.inEventLoop()) {

            next.invokeWrite(msg, promise);

        } else {

            executor.execute(() -> next.invokeWrite(msg, promise));

        }

    }

}



private void invokeWrite(Object msg, ChannelPromise promise) {

    if (invokeHandler()) {

        try {

            // 调用 ChannelOutboundHandler 的 write 方法

            ((ChannelOutboundHandler) handler()).write(this, msg, promise);

        } catch (Throwable t) {

            promise.tryFailure(t);

        }

    } else {

        write(msg, promise);

    }

}
  • 分析:
    • write:触发出站事件,传播到下一个支持 write 的上下文。
    • newPromise:创建 ChannelPromise 跟踪异步结果。
    • findContextOutbound:查找支持 write 或 flush 的上下文。
    • 线程安全:确保写操作在 EventLoop 线程中执行。
    • 异常处理:将异常设置到 promise,触发 ChannelFutureListener。
2.2.4 异常传播(fireExceptionCaught)
@Override

public ChannelHandlerContext fireExceptionCaught(Throwable cause) {

    invokeExceptionCaught(findContextInbound(MASK_EXCEPTION_CAUGHT), cause);

    return this;

}



static void invokeExceptionCaught(final AbstractChannelHandlerContext next, final Throwable cause) {

    ObjectUtil.checkNotNull(cause, "cause");

    EventExecutor executor = next.executor();

    if (executor.inEventLoop()) {

        next.invokeExceptionCaught(cause);

    } else {

        try {

            executor.execute(() -> next.invokeExceptionCaught(cause));

        } catch (Throwable t) {

            logger.warn("Failed to submit an exceptionCaught() event.", t);

            logger.warn("The exceptionCaught() event that was failed to submit was:", cause);

        }

    }

}



private void invokeExceptionCaught(Throwable cause) {

    if (invokeHandler()) {

        try {

            handler().exceptionCaught(this, cause);

        } catch (Throwable t) {

            logger.warn("An exception was thrown by a user handler's exceptionCaught() method:", t);

            logger.warn(".. and the original exception was:", cause);

        }

    } else {

        fireExceptionCaught(cause);

    }

}
  • 分析:
    • fireExceptionCaught:传播异常到下一个支持 exceptionCaught 的上下文。
    • 线程安全:在 EventLoop 线程中执行。
    • 异常处理:捕获 exceptionCaught 中的异常,避免中断管道。
2.2.5 管道操作(addLast 代理)
@Override

public ChannelPipeline pipeline() {

    return pipeline;

}
  • 分析:
    • 通过 pipeline() 访问 ChannelPipeline,支持动态添加/移除 ChannelHandler。
    • 实际操作委托给 DefaultChannelPipeline。

3. 使用场景

以下结合 HTTP 协议等场景,分析 AbstractChannelHandlerContext 的用法。

3.1 HTTP 服务器:处理请求

  • 场景:接收 HTTP 请求,发送响应。

  • 代码示例

    import io.netty.channel.*;
    
    import io.netty.handler.codec.http.*;
    
    import io.netty.util.concurrent.GenericFutureListener;
    
    
    
    public class HttpServerHandler extends SimpleChannelInboundHandler<FullHttpRequest> {
    
        @Override
    
        protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) {
    
            // 创建响应
    
            FullHttpResponse response = new DefaultFullHttpResponse(
    
                    HttpVersion.HTTP_1_1, HttpResponseStatus.OK,
    
                    Unpooled.copiedBuffer("Hello, World!", CharsetUtil.UTF_8));
    
            response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain");
    
            response.headers().set(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes());
    
    
    
            // 发送响应并监听
    
            ctx.writeAndFlush(response).addListener(new GenericFutureListener<ChannelFuture>() {
    
                @Override
    
                public void operationComplete(ChannelFuture future) {
    
                    if (future.isSuccess()) {
    
                        System.out.println("Response sent");
    
                    } else {
    
                        ctx.fireExceptionCaught(future.cause());
    
                    }
    
                }
    
            });
    
        }
    
    
    
        @Override
    
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
    
            cause.printStackTrace();
    
            ctx.close();
    
        }
    
    }
    
  • 分析:

    • 事件处理:channelRead0 接收 FullHttpRequest,通过 ctx.writeAndFlush 发送响应。
    • 异步回调:使用 GenericFutureListener 监听写入结果。
    • 异常处理:exceptionCaught 关闭通道。

3.2 HTTP 客户端:发送请求

  • 场景:发送 HTTP 请求,处理响应。

  • 代码示例:

    import io.netty.channel.*;
    
    import io.netty.handler.codec.http.*;
    
    
    
    public class HttpClientHandler extends SimpleChannelInboundHandler<FullHttpResponse> {
    
        @Override
    
        public void channelActive(ChannelHandlerContext ctx) {
    
            HttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "/");
    
            ctx.writeAndFlush(request).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
    
        }
    
    
    
        @Override
    
        protected void channelRead0(ChannelHandlerContext ctx, FullHttpResponse response) {
    
            System.out.println("Received response: " + response.status());
    
            ctx.close();
    
        }
    
    
    
        @Override
    
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
    
            cause.printStackTrace();
    
            ctx.close();
    
        }
    
    }
    
  • 分析:

    • 通道激活:channelActive 使用 ctx.writeAndFlush 发送请求。
    • 监听器:CLOSE_ON_FAILURE 确保写入失败时关闭通道。
    • 响应处理:channelRead0 处理 FullHttpResponse。

3.3 动态管道修改

  • 场景:根据协议动态调整管道。

  • 代码示例:

    import io.netty.channel.*;
    
    import io.netty.handler.codec.http.HttpServerCodec;
    
    
    
    public class DynamicPipelineHandler extends ChannelInboundHandlerAdapter {
    
        @Override
    
        public void channelRead(ChannelHandlerContext ctx, Object msg) {
    
            if (msg instanceof String && "upgrade".equals(msg)) {
    
                // 升级到 HTTP 协议
    
                ctx.pipeline().addLast(new HttpServerCodec());
    
                ctx.pipeline().remove(this);
    
            } else {
    
                ctx.fireChannelRead(msg);
    
            }
    
        }
    
    }
    
  • 分析:

    • 动态修改:通过 ctx.pipeline() 添加 HttpServerCodec,移除当前 ChannelHandler。
    • 事件传播:fireChannelRead 继续传播事件。

4. 在 HTTP 协议中的应用

以下结合 codec-http 模块,分析 AbstractChannelHandlerContext 在 HTTP 协议中的应用。

4.1 HTTP 请求解码

  • 场景:HttpServerCodec 解码 HTTP 请求,使用 ctx.fireChannelRead。

  • 源码(HttpServerCodec):

    public class HttpServerCodec extends CombinedChannelDuplexHandler<HttpRequestDecoder, HttpResponseEncoder> {
    
        @Override
    
        protected void decode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out) throws Exception {
    
            super.decode(ctx, msg, out);
    
            for (Object o : out) {
    
                ctx.fireChannelRead(o); // 传播解码后的 HttpRequest 或 HttpContent
    
            }
    
        }
    
    }
    
  • 分析:

    • decode 方法解码 ByteBuf 为 HttpRequest 或 HttpContent。
    • ctx.fireChannelRead 将消息传播到下一个 ChannelInboundHandler。

4.2 HTTP 响应编码

  • 场景:HttpResponseEncoder 编码 HTTP 响应,使用 ctx.write。

  • 源码(HttpResponseEncoder):

    @Override
    
    protected void encode(ChannelHandlerContext ctx, Object msg, ByteBuf out) throws Exception {
    
        if (msg instanceof HttpResponse) {
    
            HttpResponse res = (HttpResponse) msg;
    
            encodeInitialLine(out, res);
    
            res.headers().forEachEntry((k, v) -> out.writeString(k + ": " + v + "\r\n"));
    
            out.writeString("\r\n");
    
        }
    
        // ...
    
    }
    
  • 分析:

    • encode 方法将 HttpResponse 编码为 ByteBuf。
    • ctx.write 触发出站事件,传播到下一个 ChannelOutboundHandler。

4.3 异常处理

  • 场景:处理 HTTP 请求或响应中的异常。

  • 代码示例

    @Override
    
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
    
        if (cause instanceof HttpException) {
    
            FullHttpResponse response = new DefaultFullHttpResponse(
    
                    HttpVersion.HTTP_1_1, HttpResponseStatus.BAD_REQUEST);
    
            ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
    
        } else {
    
            ctx.fireExceptionCaught(cause);
    
        }
    
    }
    
  • 分析:

    • 异常传播:ctx.fireExceptionCaught 传播异常。
    • 错误响应:发送 400 响应并关闭通道。

5. 性能与设计分析

5.1 性能优化

  1. 单线程模型:
    • 事件在 EventLoop 线程中处理,避免锁竞争。
    • inEventLoop 检查优化任务调度。
  2. 高效传播:
    • 双向链表(next 和 prev)实现 O(1) 事件传播。
    • executionMask 优化事件查找(findContextInbound、findContextOutbound)。
  3. 资源管理:
    • ReferenceCountUtil.touch 跟踪资源。
    • SimpleChannelInboundHandler 自动释放消息。

5.2 设计亮点

  1. 解耦:
    • 分离 ChannelHandler 和管道逻辑,通过上下文交互。
  2. 灵活性:
    • 支持动态管道修改。
    • 入站/出站事件分离,清晰职责。
  3. 线程安全:
    • 所有操作在 EventLoop 线程中执行。
  4. 上下文丰富:
    • 提供 channel()、pipeline()、handler() 等访问接口。

5.3 局限性

  1. 复杂性:
    • 方法众多,需理解入站/出站事件流。
  2. 手动资源管理:
    • 开发者需确保 ByteBuf 释放。
  3. 异常处理:
    • 需显式调用 fireExceptionCaught 或处理 ChannelFuture 失败。

6. 注意事项与最佳实践

6.1 线程安全

  • 回调线程:确保 ChannelHandler 方法在 EventLoop 线程中调用。
  • 避免阻塞:不要在 channelRead 或 write 中执行耗时操作。

6.2 资源管理

  • 释放 ByteBuf:使用 ReferenceCountUtil.release 或 SimpleChannelInboundHandler。
  • 清理管道:移除 ChannelHandler 后确保无残留引用。

6.3 异常处理

  • 传播异常:使用 ctx.fireExceptionCaught。
  • 监听器:为 writeAndFlush 添加 ChannelFutureListener。

6.4 最佳实践

  • 使用 SimpleChannelInboundHandler:简化消息处理和释放。
  • 动态管道:根据协议动态调整 ChannelHandler。
  • 属性管理:使用 ctx.attr 存储状态。
Netty源码分析(三)—数据管道ChannelPipeline源码分析 Netty源码分析(三)—数据管道ChannelPipeline源码分析 ChannelPipeline数据管道是ChannelHandler数据处理器的容器,负责ChannelHandler的管理和事件的拦截与调度 个人主页:tuzhenyu’s page 原文地址:Netty源码分析(三)—数据管道ChannelPipeline源码分析 (0) Channe 阅读详情

相关推荐

Netty源码分析(三):客户端操作之发起TCP连接

发起TCP连接 经过Netty源码分析(一):客户端操作之channel()和Netty源码分析(二):客户端操作之EventLoopGroup、group()、option()后, Netty这时候大概初始化结束了,那么客户端是如何发起TCP连接的呢? 在channel方法中,我们调到connect方法会调用initAndRegister,初始化和注册channel,那么完毕且经过一些参数检查之...

1296

netty 的异常处理

1. io.netty.util.IllegalReferenceCountException: refCnt: 0, decrement: 1io.netty.util.IllegalReferenceCountException: refCnt: 0, decrement: 1 at io.netty.buffer.AbstractReferenceCountedByteBuf.releas...

masterShaw的博客 6850

netty案例,netty4.1源码分析篇五《一行简单的writeAndFlush都做了哪些事》

前言介绍 对于使用netty的小伙伴来说,ctx.writeAndFlush()再熟悉不过了,它可以将我们的消息发送出去。那么它都执行了那些行为呢,是怎么将消息发送出去的呢。 I/O Request via {@lin...

bugstack虫洞栈 1929

netty系列之:channelHandlerContext详解

文章目录简介ChannelHandlerContext和它的应用AbstractChannelHandlerContextDefaultChannelHandlerContext总结 简介 我们知道ChannelHandler有两个非常重要的子接口,分别是ChannelOutboundHandler和ChannelInboundHandler,基本上这两个handler接口定义了所有channel inbound和outbound的处理逻辑。 不管是ChannelHandler还是ChannelOutbou

程序那些事 1万+

第二章Netty,EventLoop线程切换源码分析

摘要:本文深入解析Netty的线程切换机制,揭示其基于单线程事件循环的核心设计原理。通过NioEventLoop主循环源码分析,展示其如何处理IO事件和队列任务。重点剖析Handler线程自动切换的实现机制,包括跨线程任务提交的底层逻辑,最终给出线程隔离最佳实践:IO线程仅处理轻量操作,耗时业务交由独立线程池,并通过事件循环机制保证线程安全。全文从源码层面系统阐释了Netty实现高性能线程调度的关键技术。

ywl470812087的博客 100

用itext读取PDF文件提取对应得字符串

一.maven导入jar包 <!--pdf解析start--> <dependency> <groupId>com.itextpdf</groupId> <artifactId>itextpdf</artifactId> <version>5.5.10</version...

zhanghua_chinese的博客 3698

netty Failed to submit an exceptionCaught() event异常

最近测试netty开发的服务端应用在关闭时,出现下列异常: -》###WARN#########nioEventLoopGroup-3-2###io.netty.util.internal.logging.Slf4JLogger.warn(Slf4JLogger.java:151)###Failed to submit an exceptionCaught() event.java.util.co...

weixin_34043301的博客 2008

【Excel VBA 编程】批量核对两张表格数据,行和列显示顺序均被打乱

利用数据字典在 Excel 中进行表格数据的核对,该表格含有多行多列,并且行和列顺序是打乱的,批量核对数据后将差异输出

wei1019的专栏 1293

netty的异常分析 IllegalReferenceCountException refCnt: 0, decrement: 1

在websocket关闭时经常会抛出如下异常: IllegalReferenceCountException refCnt: 0, decrement: 1

流子的专栏 2万+

WAVE格式

一.wave格式概述 Wave文件格式是用于多媒体文件存储的Microsoft RIFF(Resource Interchange FileFormat)的一个子集。每一个RIFF文件以一个文件头开始,后面是一系列数据块。Wave文件通常是包含“WAVE”块的RIFF文件。而该“WAVE”块由两个子块组成,称为“fmt”块。“fmt”块用于确定数据格式,并且“data”块包含实际的样本数据,

yejia1280的博客 4391

【Konva】解决图形加入group后无法获取到绝对坐标,以及group内绘制新图形坐标偏移的问题

解决konva绘图开发时“图形加入group后坐标不会变动,无法获取到绝对坐标”的问题

近10年前端开发工作经验,为你分享日常经验所得 1500

Netty 客户端连接源码解析

当服务端启动后,那么久可以做客户端连接的事情了。客户端的示例代码在Netty服务端启动源码解析那篇文章中已经有展示了,那么这里在回顾一下,代码如下: public class NettyClient { public static void main(String[] args) throws Exception { //客户端需要一个事件循环组 EventLoopGroup group = new NioEventLoopGroup(); tr

寒山道杳 1469

【问题解析】Matlab Function的易错点(Variable Size)

Matlab Function的易错点

CrazyRabbit的博客 9869

Netty源码(十二)之服务端向客户端写数据的过程

前面的几篇博客大致的介绍整个Netty核心的代码,以及启动的流程,服务端的读取流程,以及常用的解码器的源码。至此Netty的源码还剩一个服务端向客户端写数据的流程。今天我们就来介绍一下服务端向客户端写的流程。写的方式有以下两种,具体代码如下: ctx.writeAndFlush(""); ctx.channel().writeAndFlush(""); 1 2 这两种方式的区别具体如下图所示: 可以看到我们如果执行ctx.writeAndFlush("");方法后,当前的handler后面所

二狗家有矿 383

Ansys Circuit新手必看:IBIS模型导入时,Pin Import和Buffer Import到底怎么选?

本文详细解析了Ansys Circuit中IBIS模型导入时Pin Import与Buffer Import的选择策略,帮助SI/PI工程师根据仿真需求做出正确决策。通过对比两种方式的特性差异和应用场景,提供实用的选择指南和性能优化建议,提升信号完整性仿真效率。

weixin_26846533的博客 262

基于树莓派4B与NCNN的YOLOv8高效部署实战:无GPU环境下的C++加速优化全流程指南**

本文详细介绍了在树莓派4B上基于NCNN框架部署YOLOv8目标检测模型的全流程。内容包括:从PyTorch模型导出NCNN格式文件、树莓派环境配置(OpenCV和NCNN编译)、C++实现代码解析(含模型加载、推理及后处理),以及实际部署测试结果。在树莓派4B上达到约2FPS,并提供INT8量化、多线程等优化建议。该方案为无GPU设备提供了轻量化目标检测的实用部署方案,适合边缘计算场景。

FJN110的博客 918

Netty源码分析第4章(pipeline)---->第4节: 传播inbound事件

Netty源码分析第4章(pipeline)---->第4节: 传播inbound事件 Netty源码分析第四章: pipeline 第四节: 传播inbound事件 有关于inbound事件, 在概述中做过简单的介绍, 就是以自己为基准, 流向自己的事件, 比如最常见的channelRead事件, 就是对方发...

weixin_30318645的博客 345

UFAST车道线检测 Ultra-Fast-Lane-Detection 从环境搭建到复现完成(一)

UFAST车道线检测 Ultra-Fast-Lane-Detection 从环境搭建到复现完成(一)

m0_46364958的博客 4345

Netty学习之旅------源码分析ChannelPipeline实现原理

本文主要从如下方面展示: Nettybind源码分析 ChannelPipline链式请求源码分析 1、NettyServerBootstrapbind源码跟踪 本文将重点分析Netty服务端绑定端口流程。 1.1入口程序 1.2 AbstractBootstarp的doBind方法 初始化一个通道,并注册,如果注册失败,直接返回。 如果初始化并立即注册成功,执行...

中间件兴趣圈 3962

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

Netty中的ChannelPipeline源码分析

ChannelPipeline在Netty中是用来处理请求的责任链,默认实现是DefaultChannelPipeline,其构造方法如下: private final Channel channel; private final ChannelFuture succeededFuture; private final VoidChannelPromise voidPromise; final A...

Z_ChenChen的博客 453

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

Netty 源码分析系列(十八)一行简单的writeAndFlush都做了哪些事?

对于使用netty的小伙伴来说,我们想通过服务端往客户端发送数据,通常我们会调用ctx.writeAndFlush(数据)的方式。那么它都执行了那些行为呢,是怎么将消息发送出去的呢。在这个类中,我们主要看方法,源码如下。do {return;通过一个无限循环,保证可以拿到所有的节点上的ByteBuf,通过这个函数获取节点,我们进一步看它的实现,如下,它只会取出我们标记的节点。下面我们看下的方法源码。

初念初恋的博客 1975

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

【Netty】一行简单的writeAndFlush都做了哪些事(十八)

Netty 概述(一)Netty 架构设计(二)Netty Channel 概述(三)Netty ChannelHandler(四)ChannelPipeline源码分析(五)字节缓冲区 ByteBuf (六)(上)字节缓冲区 ByteBuf(七)(下)Netty 如何实现零拷贝(八)Netty 程序引导类(九)Reactor 模型(十)工作原理详解(十一)Netty 解码器(十二)Netty 编码器(十三)Netty 编解码器(十四)自定义解码器、编码器、编解码器(十五)Future 源码分析(十六)

DreamSun的博客 3820

Netty源码分析篇:Netty Pipeline 初始化流程

Netty源码分析篇:Netty Pipeline 初始化流程

java_rutu的博客 657

netty之写出数据源码分析

在中看了如何接收客户端的数据,以及接收数据之后的业务处理。本文来看下业务处理完成后将结果写回给客户端的相关源码逻辑。需要先启动netty源码example模块的echoserver,再启动echoclient进行debug测试。

wang0907的博客 717

netty源码分析 之五 transport(ChannelHandler)

上文说到了,channelHandler, 顾名思义 handler 处理者 从channelPipeline的定义中看出,channelPipeline是channelHandler的集合 public interface ChannelPipeline extends Iterable> 查看其接口定义和源码可以看出 接口方法 分为三类   Handler life cycle m

akfly的专栏 698
上一篇: Netty 如何实现事件驱动
下一篇: Netty中DefaultChannelPipeline源码解读
Jooou
博客等级 码龄9年 226粉丝 58原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值