netty源码浅析-数据接入与解码过程

SenseVoice 实测,阿里开源语音大模型,识别效果和效率优于 Whisper,居然还能检测掌声、笑声!5分钟带你部署体验 阿里开源语音大模型:语音识别效果和性能强于 Whisper,还能检测掌声、笑声、咳嗽等 阅读详情

数据接入与解码过程

我们接着上面分析的服务端接收到数据后的处理,其中有一步是执行pipelinefireChannelRead(byteBuf)方法,将数据传递给后面的处理流程,我们看看后面的解码过程。我们继续跟踪这个方法会走到
io.netty.channel.DefaultChannelPipeline.HeadContext#channelRead

public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            ctx.fireChannelRead(msg);
        }
 public ChannelHandlerContext fireChannelRead(final Object msg) {
        invokeChannelRead(findContextInbound(), msg);
        return this;
    }
private AbstractChannelHandlerContext findContextInbound() {
        //查找inbound的channelHandlerContext
        AbstractChannelHandlerContext ctx = this;
        do {
            ctx = ctx.next;
        } while (!ctx.inbound);
        return ctx;
    }

在pipeline组着的双向链表中查找,没有注解@Skip的channelHandlerContext,然后执行与其绑定的 channelHandler,这里就会走到io.nettyhandler.codecByteToMessageDecoder#channelRead方法

public abstract class ByteToMessageDecoder extends ChannelInboundHandlerAdapter

可以看到这个ByteToMessageDecoder本质上也是一个channelHandler,我们看一下这个抽象类的channelRead方法

public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        if (msg instanceof ByteBuf) {
            //每个线程创建一个CodecOutputList,相当于list
            CodecOutputList out = CodecOutputList.newInstance();
            try {
                ByteBuf data = (ByteBuf) msg;
                first = cumulation == null;
                if (first) {
                    //如果第一次写入累加器值未data
                    cumulation = data;
                } else {
                    //如果不是第一次写入累加器累加data值
                    cumulation = cumulator.cumulate(ctx.alloc(), cumulation, data);
                }
                //解码操作
                callDecode(ctx, cumulation, out);
            } catch (DecoderException e) {
                throw e;
            } catch (Exception e) {
                throw new DecoderException(e);
            } finally {
                //cumulation使用之后进行释放回收
                if (cumulation != null && !cumulation.isReadable()) {
                    numReads = 0;
                    cumulation.release();
                    cumulation = null;
                } else if (++ numReads >= discardAfterReads) {//读取次数超过16次则丢弃
                    // We did enough reads already try to discard some bytes so we not risk to see a OOME.
                    // See https://github.com/netty/netty/issues/4275
                    numReads = 0;
                    discardSomeReadBytes();
                }

                int size = out.size();
                decodeWasNull = !out.insertSinceRecycled();
                //向下传递
                fireChannelRead(ctx, out, size);
                out.recycle();
            }
        } else {
            ctx.fireChannelRead(msg);
        }
    }

这里可以看到首先创建了一个CodecOutputList,而这个类继承了AbstractList,也里可以理解为就是一个list,这个类里面维护了一个CODEC_OUTPUT_LISTS_POOL,这是一个FastThreadLocal,也就是每个线程会对应一个 list_pool,同时CodecOutputLists实现了CodecOutputListRecycler,这个是一个netty提供回收站功能,可以复用创建的对象。我们继续回到channelRead方法中,如果是第一写入就将data值赋值给cumulation。如果不是第一次写入直接累加器方法将新的数据累加。

private Cumulator cumulator = MERGE_CUMULATOR;
public static final Cumulator MERGE_CUMULATOR = new Cumulator() {
        @Override
        public ByteBuf cumulate(ByteBufAllocator alloc, ByteBuf cumulation, ByteBuf in) {
            final ByteBuf buffer;
            //如果cumulation可以读取的字节数小于要读取的字节数则扩展
            if (cumulation.writerIndex() > cumulation.maxCapacity() - in.readableBytes()
                    || cumulation.refCnt() > 1 || cumulation.isReadOnly()) {
                //不够放入新读取的内容,则扩展
                buffer = expandCumulation(alloc, cumulation, in.readableBytes());
            } else {
                buffer = cumulation;
            }
            buffer.writeBytes(in);
            in.release();
            return buffer;
        }
    };
static ByteBuf expandCumulation(ByteBufAllocator alloc, ByteBuf cumulation, int readable) {
        ByteBuf oldCumulation = cumulation;
        //扩展到新的需要读取的数量和之前之和
        cumulation = alloc.buffer(oldCumulation.readableBytes() + readable);
        cumulation.writeBytes(oldCumulation);
        oldCumulation.release();
        return cumulation;
    }

可以看到这里就是不停的累加新加入的数据,组成一个大的bytebuf,然后调用callDecode方法,这个是解码的核心方法,我们跟踪到这个方法

protected void callDecode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) {
        try {
            //累加器聚合的所有数据
            while (in.isReadable()) {
                int outSize = out.size();
                //如果解析出来了,则向下传播
                if (outSize > 0) {
                    fireChannelRead(ctx, out, outSize);
                    out.clear();

                    // Check if this handler was removed before continuing with decoding.
                    // If it was removed, it is not safe to continue to operate on the buffer.
                    //
                    // See:
                    // - https://github.com/netty/netty/issues/4635
                    //如果ctx已经移除则返回
                    if (ctx.isRemoved()) {
                        break;
                    }
                    outSize = 0;
                }
                //可读字节长度
                int oldInputLength = in.readableBytes();
                //由子类重写解析方法
                decodeRemovalReentryProtection(ctx, in, out);

                // Check if this handler was removed before continuing the loop.
                // If it was removed, it is not safe to continue to operate on the buffer.
                //
                // See https://github.com/netty/netty/issues/1664
                if (ctx.isRemoved()) {
                    break;
                }
                //解析失败则直接跳出解析方法
                if (outSize == out.size()) {
                    if (oldInputLength == in.readableBytes()) {
                        break;
                    } else {
                        continue;
                    }
                }

                if (oldInputLength == in.readableBytes()) {
                    throw new DecoderException(
                            StringUtil.simpleClassName(getClass()) +
                                    ".decode() did not read anything but decoded a message.");
                }
                //如果只有一个解码器
                if (isSingleDecode()) {
                    break;
                }
            }
        } catch (DecoderException e) {
            throw e;
        } catch (Exception cause) {
            throw new DecoderException(cause);
        }
    }

可以看到这里会循环读取bytebuf中的数据,然后执行解码操作,如果成功解码出来了数据,就继续触发后续的 channeRead方法将解码出来的数据往后传递处理,如果在解析过程中解析失败了则会跳出当前的解码过程,同时如果解码过程中ChannelHandlerContext被移除了也会直接跳出循环。我们继续跟踪到正在的解码代码中

final void decodeRemovalReentryProtection(ChannelHandlerContext ctx, ByteBuf in, List<Object> out)
            throws Exception {
        decodeState = STATE_CALLING_CHILD_DECODE;
        try {
            //由子类重写,解析出来的结果放入out中
            decode(ctx, in, out);
        } finally {
            boolean removePending = decodeState == STATE_HANDLER_REMOVED_PENDING;
            decodeState = STATE_INIT;//恢复初始状态
            if (removePending) {
                handlerRemoved(ctx);
            }
        }
    }

这里我们看到有个decode方法,解码就在这里执行

protected abstract void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception;

他是一个抽象方法,由子类来扩展真正的解码逻辑。 我们也可以自己重写这个解码器实现自定义的解码逻辑。我
们这里看一下最简单的解码器StringDecoder,他继承了另一个解码类。

protected void decode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out) throws Exception {
        out.add(msg.toString(charset));
    }

可以看到就是简单的将转换为指定编码的String,然后添加到结果集List中。 同时netty提供了几个默认的解码器
我们先来看看LineBasedFrameDecoder

 protected Object decode(ChannelHandlerContext ctx, ByteBuf buffer) throws Exception {
        //查找/\r\n或者\n的位置
        final int eol = findEndOfLine(buffer);
        if (!discarding) {
            if (eol >= 0) {
                final ByteBuf frame;
                //获取可读长度
                final int length = eol - buffer.readerIndex();
                //判断/\r\n或者\n,如果是前者则分隔符占用两个字节
                final int delimLength = buffer.getByte(eol) == '\r'? 2 : 1;
                //需要读取的换行符长度,大于了最大长度
                if (length > maxLength) {
                    //跳过这部分,从分隔符后开始在读
                    buffer.readerIndex(eol + delimLength);
                    fail(ctx, length);//记录跳过长度,并输出异常信息
                    return null;
                }
                //跳过换行符
                if (stripDelimiter) {
                    //截取可读字节长度的buffer
                    frame = buffer.readRetainedSlice(length);
                    //跳过换行符长度
                    buffer.skipBytes(delimLength);
                } else {
                    //不跳过换行符
                    frame = buffer.readRetainedSlice(length + delimLength);
                }

                return frame;
            } else {
                //如果没有发现换行符
                final int length = buffer.readableBytes();
                //读取长度大于最大读取长度则丢弃
                if (length > maxLength) {
                    discardedBytes = length;
                    //修改读索引
                    buffer.readerIndex(buffer.writerIndex());
                    discarding = true;
                    offset = 0;
                    //如果快速失败则直接记录异常信息
                    if (failFast) {
                        fail(ctx, "over " + discardedBytes);
                    }
                }
                return null;
            }
        } else {
            //如果是丢弃模式
            if (eol >= 0) {
                //如果有换行符,记录丢弃长度
                final int length = discardedBytes + eol - buffer.readerIndex();
                final int delimLength = buffer.getByte(eol) == '\r'? 2 : 1;
                buffer.readerIndex(eol + delimLength);
                discardedBytes = 0;
                discarding = false;
                if (!failFast) {
                    fail(ctx, length);
                }
            } else {
                //没有换行符,则直接加上可读长度
                discardedBytes += buffer.readableBytes();
                buffer.readerIndex(buffer.writerIndex());
            }
            return null;
        }
    }

decode方法是正在解析接入数据的方法,我们先分开来看上面的代码

private int findEndOfLine(final ByteBuf buffer) {
        //可读长度
        int totalLength = buffer.readableBytes();
        //查找\n
        int i = buffer.forEachByte(buffer.readerIndex() + offset, totalLength - offset, ByteProcessor.FIND_LF);
        //判断\n的前面一个是不是\r,如果是就将查找到的位置-1
        if (i >= 0) {
            offset = 0;
            if (i > 0 && buffer.getByte(i - 1) == '\r') {
                i--;
            }
        } else {
            offset = totalLength;
        }
        return i;
    }

由于我们是行解码器,所以这里先查找换行分隔符,分隔符分为两种\n和\rn,所以这里先查找\n的位置,如果查找到后在查看前面的是不是\r如果是就将查询到的位置减1,如果不是就直接返回查找到的位置,如果没有查找到则返回-1。

if (!discarding) {
            if (eol >= 0) {
                final ByteBuf frame;
                //获取可读长度
                final int length = eol - buffer.readerIndex();
                //判断/\r\n或者\n,如果是前者则分隔符占用两个字节
                final int delimLength = buffer.getByte(eol) == '\r'? 2 : 1;
                //需要读取的换行符长度,大于了最大长度
                if (length > maxLength) {
                    //跳过这部分,从分隔符后开始在读
                    buffer.readerIndex(eol + delimLength);
                    fail(ctx, length);//记录跳过长度,并输出异常信息
                    return null;
                }
                //跳过换行符
                if (stripDelimiter) {
                    //截取可读字节长度的buffer
                    frame = buffer.readRetainedSlice(length);
                    //跳过换行符长度
                    buffer.skipBytes(delimLength);
                } else {
                    //不跳过换行符
                    frame = buffer.readRetainedSlice(length + delimLength);
                }

                return frame;
            } else {
                //如果没有发现换行符
                final int length = buffer.readableBytes();
                //读取长度大于最大读取长度则丢弃
                if (length > maxLength) {
                    discardedBytes = length;
                    //修改读索引
                    buffer.readerIndex(buffer.writerIndex());
                    discarding = true;
                    offset = 0;
                    //如果快速失败则直接记录异常信息
                    if (failFast) {
                        fail(ctx, "over " + discardedBytes);
                    }
                }
                return null;
            }
        }

如果是非丢弃模式,默认是费丢弃模式,如果查找到了换行符,计算可以读取的长度,计算换行分隔符长度,并且判断如果读取的长度大于了设置的最大读取长度就跳过这段内容,从分隔符后开始在读取,然后将异常在 pipeline中向后传播,返回null。如果长度没有查过最大长度,而且要跳过分隔符,就先截取可以读取的字节长度的bytebuf,跳过分隔符,然后返回,如果是不跳过分隔符,则连带着换行分隔符和数据本身一起返回。如果没有在查询过程中没有查找到换行分隔符,判断传入数据的可读取长度如果大于最大可读长度则直接将跳过这段数据然后设置为丢弃模式,记录丢弃的长度,如果快速失败则将异常信息向后传递,如果没有超出返回null值。

else {
            //如果是丢弃模式
            if (eol >= 0) {
                //如果有换行符,记录丢弃长度
                final int length = discardedBytes + eol - buffer.readerIndex();
                final int delimLength = buffer.getByte(eol) == '\r'? 2 : 1;
                buffer.readerIndex(eol + delimLength);
                discardedBytes = 0;
                discarding = false;
                if (!failFast) {
                    fail(ctx, length);
                }
            } else {
                //没有换行符,则直接加上可读长度
                discardedBytes += buffer.readableBytes();
                buffer.readerIndex(buffer.writerIndex());
            }
            return null;
        }

如果是丢弃模式,并且查找到了换行符则将这段数据内容包括换行分隔符一起丢弃,如果设置非快速失败则,向后传递解码异常信息。没有发现换行符,则设置丢弃长度为之前的丢弃长度加上当前数据的可读长度,并且直接将读索引设置为写索引,也就跳过了这段读取内容,然后null。
netty提供的解码器还有很多种不如:基于特定分隔符的DelimiterBasedFrameDecoder、基于特定长度的
FixedLengthFrameDecoder、基于pb文件的ProtobufDecoder等等我们这里不再详细介绍,如果感兴趣可以自己阅读codec下的内容。如果有分析错误的地方还请不吝指正。感谢!!!

五步通关!宝塔Linux部署ASP.NET Core的魔法秘籍大公开! 摘要: 本文提供ASP.NET Core应用五步部署攻略,涵盖从环境配置到线上运行的完整流程: 1️⃣ 环境准备:安装宝塔面板、ASP.NET Core运行时及开放端口; 2️⃣ 应用发布:通过dotnet publish生成独立部署包并上传服务器; 3️⃣ Nginx配置:设置反向代理将域名请求转发至应用端口; 4️⃣ 进程守护:使用Supervisor确保应用持续运行; 5️⃣ HTTPS加密:通过宝塔快速申请SSL证书并解决验证路径冲突。 关键点: 强调权限设置(755)、端口开放及反向代理细节; 提 阅读详情

相关推荐

2024年上市公司ESG评级全解析:六大权威数据源横向对比与应用指南

本文深度解析2024年国内主流ESG评级数据源,包括华证、商道融绿、Wind、富时罗素和彭博,横向对比其覆盖范围、评分逻辑与应用侧重点。文章提供实战指南,帮助投资者与企业根据投资决策、风险管理和学术研究等不同场景,精准选择并有效应用ESG数据,实现从概念到实用分析工具的转变。

weixin_29229055的博客 311

Netty的解码器和编码器

他会按照自定义分隔符将ByteBuf数据包进行拆分基于灵活长度的数据包,在ByteBuf数据包中,加了一个长度字段,保存了原始数据包长度,解码的时候,会按照这个长度进行原始数据包的提取。一般基于Header-Content协议的数据包,都建议使用这个解码器//发送的数据包最大长度//长度字段偏移量//长度字段自己占用的字节数//长度字段的偏移量矫正,比如长度后面还有两个字节用于存储别的信息,那么该值为2//丢弃的起始字节数...

终身做学习,并予以实践 3486

Camera tuning flow相机调试流程

相机调试流程分为三大模块:ProcessRaw处理原始数据(黑电平校正、阴影校正),3A实现自动控制(曝光/对焦/白平衡),ISP进行图像精加工(伽马校正、锐化降噪、色彩处理)。三个阶段环环相扣,前阶段为后阶段提供基础,最终输出画质优良且风格化的图像。

weixin_64706696的博客 1229

Netty编解码器,Netty自定义编解码器解决粘包拆包问题,Netty编解码器的执行过程详解

当Netty发送或者接收一个消息的时候,就会发生一次数据转换。入站消息会被解码(从字节转换为另一种格式,比如java对象);出站消息会被编码成字节。Netty 提供一系列实用的编解码器,他们都实现了 ChannelInboundHadnler 或者 ChannelOutboundHandler 接口。在这些类中,channelRead 方法已经被重写了。以入站为例,对于每个从入站 Channel 读取的消息,这个方法会被调用。

秃了也弱了 1477

Android音频学习(十四)——加载音频设备

loadHwModule 是 Android 音频系统的核心初始化函数,负责加载音频硬件抽象层(HAL)的模块实现。它建立 AudioPolicyService 与底层硬件的桥梁,将配置文件(audio_policy_config.xml)中的标签<module>定义转化为可操作的硬件对象,加载的是音频硬件模块(HAL实现),每个模块对应一种音频设备类型,以动态库的形式存在,负责与底层音频硬件交互。

miemie2014的博客 1730

上下文理解的AI增强方案:AI应用架构师的架构洞察

本文将从AI应用架构师的视角,深入探讨“上下文理解”的技术本质、核心挑战,以及一套可落地的上下文增强架构方案。我们会拆解上下文理解的底层需求,分析架构设计中的关键决策,并通过具体案例展示如何构建一个能“记住过去、理解现在、预测未来”的AI系统。三个维度:上下文的内容范围(短期/中期/长期)、数据类型(文本/结构化/多模态)、技术挑战(窗口限制/信息过载/跨会话一致性);三种架构模式:分层上下文存储(热/冷数据分离)、上下文路由(按需筛选)、动态压缩(适配模型窗口);四个关键组件。

欢迎来到我的优快云空间!这里聚焦AI大模型应用实战,分享前沿技术、实战案例与开发经验。 219

Netty使用篇:自定义编解码器

Netty使用篇:自定义编解码器

七叔的博客 2万+

GDI文字绘制和windows下opengl文字绘制小结

GDI绘制文字,要设置文字的属性,主要就是通过设置DC中的font对象来实现的。 font对象的创建可以由createfont()、createfontIndirect()来实现。 HFONT CreateFont( int nHeight, // height of font int nWidth, // average

T_W_S的专栏 5321

吃透Netty源码系列四十之CodecOutputList

吃透Netty源码系列四十之CodecOutputListCodecOutputList是什么重要属性回收器线程本地变量CodecOutputListsnewInstance获取CodecOutputList对象构造方法get有检查获取消息对象getUnsafe无检查获取消息对象insert插入对象到指定位置add添加对象到最后add添加对象到指定位置remove删除指定位置的对象clear清空r...

王伟王胖胖的博客 1456

智算中心建设项目初步设计方案

本项目面向区级政府、智算中心及文旅从业者,聚焦某区智算中心一期建设,响应数字经济与智慧城市建设政策,推动文旅产业升级。遵循统筹规划、数据驱动原则,目标打造智慧文旅样板。建设内容涵盖云网数据底座(以租代建)、数据中台(全生命周期管理)、智慧文旅平台(含“一机游”电商)及气象监测等配套,采用前后端架构与低代码开发,强化三级等保与纵深防御,实现安全可控。方案融合多类资源目录,提供从设计到运营的完整技术支撑,助力区域智算与文旅深度融合。

cdfunlove的博客 111

YOLOv11改进策略【独家融合改进】| MobileNetV4+BiFPN,轻松实现降参涨点,适用专栏内所有的骨干替换

可扩展的高效物体检测BiFPN(加权双向特征金字塔网络)

Limiiiing的博客 2357

【Netty】 工作原理详解(十一)

Netty 概述(一)Netty 架构设计(二)Netty Channel 概述(三)Netty ChannelHandler(四)ChannelPipeline源码分析(五)字节缓冲区 ByteBuf (六)(上)字节缓冲区 ByteBuf(七)(下)Netty 如何实现零拷贝(八)Netty 程序引导类(九)Reactor 模型(十)本篇文章主要讲解了 Netty 的工作原理及简单应用。下节我们来讲解 Netty 的编解码。。

DreamSun的博客 3339

QMK固件OLED显示屏配置教程:从零开始实现个性化键盘显示(实操部分)

本教程详细介绍了如何从零开始配置QMK固件的OLED显示屏,实现个性化键盘显示。首先,文章解释了OLED显示屏的基本概念及其在键盘中的应用,并介绍了I2C和SPI两种通信方式。接着,教程逐步指导用户如何在QMK固件中启用OLED功能,包括在rules.mk中启用OLED、在halconf.h和mcuconf.h中配置I2C功能,以及在config.h中设置I2C和OLED参数。最后,教程展示了如何在keymap.c中编写代码,实现OLED显示内容,并提供了进阶定制功能,如显示当前层信息、按键状态和QMK L

Despacito0o的博客 578

netty 4.1.34 源码浅析1

netty 4.1.34 源码浅析1 概述 参考 https://netty.io/wiki/user-guide-for-4.x.html https://github.com/netty/netty https://www.infoq.cn/article/netty-threading-model#mainLogin netty权威指南(第二版) 背景知识 单线程、多线程、线程...

undergrowth的专栏 938

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

IMSL CNL 7.0.0 (x86-64)Crack

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

Netty常用基础解码器(处理半包/粘包源码浅析)

本文详细介绍了Netty中的两种帧解码器:FixedLengthFrameDecoder和LineBasedFrameDecoder。FixedLengthFrameDecoder是固定长度的帧解码器,通过指定帧的固定字节长度来分割数据;LineBasedFrameDecoder是基于行分隔符的帧解码器,通过"\n"或"\r\n"来识别消息边界。文章从属性、构造方法到核心解码逻辑进行了深入解析,包括如何处理超过最大帧长度的情况、是否保留分隔符等细节,为理解Net

pscool的博客 770

假人有限元模型

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

Netty浅析

Netty是JBoss出品的高效的Java NIO开发框架。本文将主要分析Netty实现方面的东西,由于精力有限,本人并没有对其源码做了极细致的研 究。如果下面的内容有错误或不严谨的地方,也请指正和谅解。对于Netty使用者来说,Netty提供了几个典型的example,并有详尽的API doc和guide doc,本文的一些内容及图示也来自于Netty的文档,特此致谢。 1、总体结构 先...

javaxuexi123的博客 273

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

Netty 源码中对 Redis 协议的实现

原文地址: haifeiWu的博客 博客地址:www.hchstudio.cn 欢迎转载,转载请注明作者及出处,谢谢! 近期一直在做网络协议相关的工作,所以博客也就与之相关的比较多,今天楼主结合 Redis的协议 RESP 看看在 Netty 源码中是如何实现的。 RESP 协议 RESP 是 Redis 序列化协议的简写。它是一种直观的文本协议,优势在于实现非常简单,解析性...

whfstudio的博客 533

一起学Netty(八)之 浅析ByteToMessageDecoder

上一节一起学习了几个解码器,用于解决TCP协议网络传输过程中粘包和拆包的问题,用过Netty的人总会说一句话“用Netty一定要了解一下它的底层原理,这样才敢用”,其实很有感悟,Netty in action 这本书中也有一个章节分析了codec,也定义了几个自定义的译码器,但是它自定义的几个译码器全部是继承与ByteToMessageDecoder的,我们上文中的几个解码器例如DelimiterBasedFrameDecoder,FixedLengthFrameDecoder,LineBasedFrame

BazingaLyncc 1万+

java NIO Netty实现原理浅析(转)

Netty实现原理浅析(转)<br />本文将主要分析Netty实现方面的东西,由于精力有限,本人并没有对其源码做了极细 致的研 究。如果下面的内容有错误或不严谨的地方,也请指正和谅解。对于Netty使用者来说,Netty提供了几个典型的example,并有详尽的API doc和guide doc,本文的一些内容及图示也来自于Netty的文档,特此致谢。1、总体结构<br /><br />先放上一张漂亮的Netty总体结构图,下面的内容也主要围绕该图上的一些核心功能做分析, 但对如Contai

Zfrong繁荣的IT技术、IT项目、解决方案专栏Blog-上海 5568

Netty实现原理浅析

JBoss出品的高效的Java NIO开发框架,关于其使用,可参考我的另一篇文章netty使用初步。 本文将主要分析Netty实现方面的东西,由于精力有限,本人并没有对其源码做了极细致的研 究。如果下面的内容有错误或不严谨的地方,也请指正和谅解。对于Netty使用者来说,Netty提供了几个典型的example,并有详尽的API doc和guide doc,本文的一些内容及图示也来自于...

abcd_0207的博客 218

Netty 之 浅析ByteToMessageDecoder

上一节一起学习了几个解码器,用于解决TCP协议网络传输过程中粘包和拆包的问题,用过Netty的人总会说一句话“用Netty一定要了解一下它的底层原理,这样才敢用”,其实很有感悟,Netty in action 这本书中也有一个章节分析了codec,也定义了几个自定义的译码器,但是它自定义的几个译码器全部是继承与ByteToMessageDecoder的,我们上文中的几个解码器例如Delimiter

z69183787的专栏 1万+

HttpObjectDecoder&HttpObjectEncoder源码浅析&示例

HttpObjectDecoder是Netty中用于解析HTTP消息的解码器,主要包含请求行/响应行、请求头/响应头的解析逻辑。其核心组件包括:1)定义默认配置常量,如最大行长度、分块大小等;2)使用状态机(State枚举)控制解析流程;3)通过HeaderParser和LineParser实现行和头的具体解析。解析过程支持分块传输、长度校验等功能,采用字符序列缓存数据并处理各种边界情况,如控制字符跳过、分块消息处理等。该解码器可灵活配置参数,确保高效可靠地解析HTTP协议消息。

pscool的博客 498

netty中责任连模式浅析

netty中的责任连模式

clz1314521的专栏 227

WebSocketFrameEncoder&WebSocketFrameDecoder源码浅析

HTTP已经诞生了数十年,具有广泛的应用,各种优化专门的优化机制也已经被浏览器及服务器等设备实施,XHR 请求自然而然就继承了所有这些功能。然而,对于只使用HTTP协议完成升级协商的WebSocket来说,流式数据处理可以让我们在客户端和服务器间自定义协议,但也会错过浏览器提供的很多服务,应用可能必须实现自已的逻辑来填充某些功能空白,比如缓存、状态管理、元数据交付等等。

pscool的博客 394
上一篇: netty源码浅析-服务端数据接入
下一篇: netty源码浅析-byteBuf介绍
胖柯G
博客等级 码龄10年 453粉丝 57原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值