Netty中的HttpServerCodec和HttpObjectAggregator

news2025/1/17 4:11:39

首先使用Netty搭建一个HttpServer,代码如下:

public class App {
    public static boolean useEpoll = false;

    static {
        String os = System.getProperty("os.name");

        if (Objects.nonNull(os) && os.equalsIgnoreCase("linux") &&
                Epoll.isAvailable()) {
            useEpoll = true;
        }
    }


    public static void main(String[] args) throws InterruptedException {
        System.out.println("starting...");
        nettyMain();
    }

    public static void nettyMain() throws InterruptedException {

        EventLoopGroup boss = buildBossEventLoopGroup();
        EventLoopGroup worker = buildWorkerEventLoopGroup();

        try {
            ServerBootstrap serverBootstrap = new ServerBootstrap();

            serverBootstrap
                    .group(boss, worker)
                    .channel(useEpoll ? EpollServerSocketChannel.class : NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) {
                            ch.pipeline()
                                    .addLast(new LoggingHandler(LogLevel.INFO))
                                    .addLast(new IdleStateHandler(0, 0, 5, TimeUnit.SECONDS))
                                    .addLast(new HttpServerCodec())
                                    .addLast(new HttpObjectAggregator(5*1024))
                                    // 自定义业务handler
                                    .addLast(new TestChannelHandler());
                        }
                    })
                    .childOption(ChannelOption.SO_KEEPALIVE, true);

            ChannelFuture sync = serverBootstrap.bind(8081).sync();
            System.out.println("started!");
            sync.channel().closeFuture().sync();
        } finally {
            boss.shutdownGracefully();
            worker.shutdownGracefully();
        }

    }

    public static EventLoopGroup buildBossEventLoopGroup() {
        return useEpoll ? new EpollEventLoopGroup(1) : new NioEventLoopGroup(1);
    }

    public static EventLoopGroup buildWorkerEventLoopGroup() {
        return useEpoll ? new EpollEventLoopGroup() : new NioEventLoopGroup();
    }
    
}

其中业务处理的handler如下:

@Sharable
public class TestChannelHandler extends SimpleChannelInboundHandler<FullHttpRequest> {

    public static Gson gson = new Gson();

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest msg) {
        String requestData = msg.content().toString(CharsetUtil.UTF_8);
        System.out.println("received data: " + requestData);


        ResponseData res = new ResponseData();
        res.setIntValue(200);
        res.setData("received data: " + requestData);

        // return
        FullHttpResponse response = new DefaultFullHttpResponse(
                HttpVersion.HTTP_1_1, HttpResponseStatus.OK,
                Unpooled.copiedBuffer(gson.toJson(res), CharsetUtil.UTF_8));
        response.headers().set(HttpHeaderNames.CONTENT_TYPE, "application/json;charset=UTF-8");
        // *****重要,必须加******
        // 否则客户端会一直转圈圈
        response.headers().set(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes());

        ctx.writeAndFlush(response).addListener(channelFuture -> System.out.println("writeAndFlush succeed"));

    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        ctx.flush();
    }


    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        ctx.close();
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent idleStateEvent = (IdleStateEvent) evt;
            if (idleStateEvent.state().equals(IdleState.ALL_IDLE)) {
                ctx.close();
            }
        }
    }
}

作为HttpServer,需要加入来自client的Request的Http协议的Decoder和server回复Response的Http协议的Encoder,而这两个部分集成在了Netty提供的HttpServerCodec中,来看类图结构:
在这里插入图片描述
HttpServerCodec肩负Inbound和Outbound的功能,而HttpServerCodec本身不实现两个功能,而是委托给了两个内部类完成:
在这里插入图片描述
以HttpServerRequestDecoder为例,该类类图结构如下:
在这里插入图片描述
可以看出,这两个内部编码解码类同样是ChannelHandler. 同时该类继承自HttpObjectDecoder extends ByteToMessageDecoder,而ByteToMessageDecoder是一个通用的decoder,可以自定义decoder将bytes转化为自己的数据类型,而一个数据类型一般由多个bytes组合而成,那么如何划分界限呢?常用的DelimiterBasedFrameDecoder, FixedLengthFrameDecoder都继承自该类,而这里HttpObjectDecoder 提供了解码生成HttpMessageHttpContent的方法。先来看ByteToMessageDecoder的注释:

decodes bytes in a stream-like fashion from one ByteBuf to an other Message type.
Be aware that sub-classes of ByteToMessageDecoder MUST NOT annotated with @Sharable. Some methods such as ByteBuf.readBytes(int) will cause a memory leak if the returned buffer is not released or added to the out List. Use derived buffers like ByteBuf.readSlice(int) to avoid leaking memory.

来看HttpObjectDecoder的注释:

Decodes ByteBufs into HttpMessages and HttpContents.
prevents excessive memory consumption;
control parsing behavior;
Chunked Content.
If you prefer not to handle HttpContents by yourself for your convenience, insert HttpObjectAggregator after this decoder in the ChannelPipeline. However, please note that your server might not be as memory efficient as without the aggregator.

HttpObjectDecoder会将一个Http请求分为多个数据类型,如请求头、请求体、数据过大时分片(有限状态机实现),后续的ChannelHandler可以根据不同的类型来处理,如果想直接处理完整的Http请求,可在pipeline后面加上HttpObjectAggregator(只处理入站请求),该类会聚合一个请求的所有东西生成一个FullHttpRequest供后续InboundChannelHandler使用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/435339.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Git分支篇git branch和git checkout

分支作用 在开发过程中&#xff0c;项目往往由多人协同开发&#xff0c;那么将多人编写的代码汇总到一起就成了一个困难且复杂的工作&#xff0c;另外项目也需要备份和版本迭代&#xff0c;因此不能只有一个版本。因此分支就成为了优秀的解决方案。 分支相互独立&#xff0c;…

C++STL详解(九)--使用红黑树封装实现set和map

文章目录 控制底层红黑树模板参数模板参数中的仿函数map,set中的正向迭代器map,set中的反向迭代器[]下标访问运算符重载map的模拟实现代码map的模拟实现适用map,set容器的底层红黑树代码(修改版本) 控制底层红黑树模板参数 如果我们用一棵KV模型的红黑树同时实现map和set,我们…

【数据结构】八大排序算法(梭哈)

目录 1.直接插入排序2. * 希尔排序关于希尔排序的时间复杂度 3.选择排序4. * 堆排序5.冒泡排序6. * 快速排序6.1递归快排6.1.1 hoare版6.1.2 挖坑法6.1.3 前后指针法6.1.4 关于每个区间操作的结束位置总是小于key6.1.5 关于有序原数据的效率优化 6.2 非递归快排 7. * 归并排序7…

计算机网络考试复习——第五章

本章考察范围为5.1 5.3 5.4这三部分。 该层传输的单位是报文段 5.1 运输层协议概述&#xff1a; 5.1.1 进程之间的通信&#xff1a; 运输层是向它上面的应用层提供通信服务。它属于面向通信部分的最高层&#xff0c;同时也是用户功能的最低层。 屏蔽作用&#xff1a;运输层…

flutter系列之:如何自定义动画路由

文章目录 简介自定义跳转使用flutter动画基础实现一个自定义的route总结 简介 flutter中有默认的Route组件&#xff0c;叫做MaterialPageRoute&#xff0c;一般情况下我们在flutter中进行跳转的话&#xff0c;只需要向Navigator中传入一个MaterialPageRoute就可以了。 但是Ma…

让你的three.js动起来

让你的three.js动起来 简介 本节主要是给实例添加动画效果&#xff0c;以及加了一些小插件用以实现帧率检测、gui可视化配置、动态监听屏幕大小变化刷新和鼠标操控功能。 引入的插件js&#xff1a; three.jsdat.gui.jsStats.jsTrackballControls.js 实际效果&#xff1a; …

Java 线程状态有哪些?

文章目录 Java 线程状态有哪些&#xff1f;初始状态&#xff08;NEW&#xff09;可运行状态&#xff08;RUNNABLE&#xff09;就绪状态运行状态 阻塞状态&#xff08;BLOCKED&#xff09;等待状态&#xff08;WAITING&#xff09;超时等待&#xff08;TIMED_WAITING&#xff09…

一次打靶场记录

题目提示 1、目录爆破 在对靶场进行信息收集、目录扫描之后发现结果存在www.zip,data.zp 两个备份文件 下载回来解压之后发现www.zip是网站备份文件&#xff0c;data.zip是数据库文件&#xff0c;存在一个maccms的数据库 苹果cms的数据库&#xff0c;导入本地数据库。 admin…

【并发编程Python】为什么Python这么慢

Python速度慢的所有原因 Python作为一门非常优秀的计算机语言&#xff0c;其速度慢给Python减了很多分&#xff0c;也是其一直被诟病的主要原因之一&#xff0c;通常情况下&#xff0c;Python比Java/C慢约5-10倍&#xff0c;在一些特殊的情况下Python甚至比C慢100~200倍&#x…

数据结构——B树和B+树

数据结构——B树和B树 一、B树1.B树的特征2.B树的插入操作3.B树的删除操作4.B树的缺点 二、B树B树的特征 平衡二叉树或红黑树的查找效率最高&#xff0c;时间复杂度是O(nlogn)。但不适合用来做数据库的索引树。 因为磁盘和内存读写速度有明显的差距&#xff0c;磁盘中存储的数…

玩转肺癌目标检测数据集Lung-PET-CT-Dx ——③整理、验证数据,建立Dataset对象

文章目录 数据整理整理出所有的dcm文件整理出所有的xml标注文件整理数据①——舍弃错误的标注文件整理数据②——两个标注文件指向同一个目标图片的情况封装函数&#xff0c;传入xml文件&#xff0c;显示标注效果 整理数据③——将PETCT的三通道图像转成平扫CT的单通道图像格式…

企业费控,驶向「一体化」

在数字化于企业内部各个环节实现平权、成为标配的当下&#xff0c;财务&#xff0c;这个被称为“控制企业生命力”的核心环节&#xff0c;是否应该拥有新的价值&#xff1f; 作者| 皮爷 出品|产业家 2022年年中&#xff0c;施伟和分贝通的团队接到一项“特殊需求”。 这个…

在职读研专业——劳动经济学

研究方向&#xff1a;劳动经济学主要研究劳动力市场现象及其所引起的劳动力资源配置等相关问题&#xff0c;包括劳动力供给、劳动力需求、就业、工资、人力资本投资、收入分配等。例如&#xff1a;劳动力市场失衡背后各种因素的变化&#xff0c;如何通过资源的配置使劳动资源配…

MySQL innobackupex 备份工具使用总结

前言 在MySQL备份以及搭建从库的过程中&#xff0c;我们针对比较小的库大多采用的是mysqldump&#xff0c;简单&#xff0c;方便。但是在大库进行搭建从库的时候&#xff0c;且数据库主机没有一个很好的存储来满足备份&#xff0c;这个时候就需要使用innobackupex来协助你来做一…

Pocsuite3框架POC/EXP编写练习:Flask(Jinja2) 服务端模板注入漏洞

Pocsuite3 是由知道创宇 404 实验室打造的一款基于 GPLv2 许可证开源的远程漏洞测试框架。可以用来编写POC/EXP&#xff0c;今天借助Flask框架下的SSTI漏洞练习记录一下Pocsuite3框架的配置和编写过程。 官方文档&#xff1a;Pocsuite3 是什么&#xff1f; | Pocsuite3 安装 …

小黑继续跟着沛奇老师学携程:携程基础3

3.异步编程 3.1事件循环 理解成一个死循环&#xff0c;去检测并执行某些代码 # 伪代码任务列表 [任务1&#xff0c;任务2&#xff0c;任务3&#xff0c;...] while True:可执行的任务列表&#xff0c;已完成的任务列表 去任务列表中检查所有任务&#xff0c;将可执行和已完…

安装、启动和登陆doccano

一、安装 1、使用的Pycharm安装的doccano 2、初始化数据库 doccano init 3、创建用户名和密码 # admin是用户名&#xff0c;pass是密码&#xff0c;都可以自定义 doccano createuser --username admin --password pass 二、启动 1、在一个Terminal终端启动webserver服务 …

自适应控制专栏目录及介绍

目录 自适应控制专栏目录及介绍第一篇&#xff1a;[具有不确定参数系统的自适应跟踪控制设计_ADi_hhh的博客-CSDN博客](https://blog.csdn.net/qq_45830323/article/details/129713051)第二篇&#xff1a;[&#xff08;SISO&#xff09;单输入单输出系统的模型参考自适应控制_A…

cdh Hue集成sentry的权限管理详细步骤

hue登录hue的第一个用户要用hue用户创建,默认hue为超级用户,hue用户页面的权限可以管理很多用户操作,比如查看hdfs目录,使用其他组件,授权功能等等 一.hive的配置 1.关闭模拟,开启sentry 2.添加配置(注意配置的位置) <property> <name>sentry.hive.tes…

【C++11】lambda表达式

目录 lambda表达式 1.1 lambda表达式出现的原因 1.2 lambda表达式语法 1.3 函数对象与lambda表达式 lambda表达式 1.1 lambda表达式出现的原因 在C98中&#xff0c;如果想要对一个数据集合中的元素进行排序&#xff0c;可以使用 std::sort 方法 测试代码 #include <…