简介

netty为我们提供了很多http2的封装,让我们可以轻松的搭建出一个支持http2的服务器。其中唯一需要我们自定义的就是http2 handler。

在之前的文章中,我们介绍了自定义http2handler继承自Http2ConnectionHandler并且实现Http2FrameListener。这种实现方式是netty目前比较推荐的实现方式,今天给大家介绍的一种实现方式是netty中准备替换继承Http2ConnectionHandler的实现方式,但是这种实现方式并不成熟,还在不断的完善中。

今天给大家介绍一下这种实现方式。

Http2FrameCodec

这种实现方式的核心类是Http2FrameCodec。事实上Http2FrameCodec也是继承自Http2ConnectionHandler。

它的主要作用是将HTTP/2中的frames和Http2Frame对象进行映射。Http2Frame是netty中对应所有http2 frame的封装,这样就可以在后续的handler中专注于处理Http2Frame对象即可,从而摆脱了http2协议的各种细节,可以减少使用者的工作量。

对于每个进入的HTTP/2 frame,Http2FrameCodec都会创建一个Http2Frame对象,并且将其传递给channelRead方法,用于对该对象进行处理。

通过调用write方法,可以对outbound的 Http2Frame 转换成为http2 frame的格式。

Http2Frame、Http2FrameStream和Http2StreamFrame

netty中有三个非常类似的类,他们是Http2Frame、Http2FrameStream和Http2StreamFrame。

我们知道netty中一个tcp连接可以建立多个stream,Http2FrameStream就是和stream对应的类,这个类中包含了stream的id和stream当前的状态。

一个stream中又包含了多个消息,每个消息都是由多个frame组成的,所以Http2Frame是和这些frame对应的netty类。

Http2StreamFrame本身也是一个frame,事实上它继承自Http2Frame。

为什么会有这个类呢?因为对应frame本身来说,一般情况下它是和一个特定的stream相关联的,Http2StreamFrame表示这种关联关系,可以通过它的set stream方法来指定其关联的stream。如果想要该frame应用到整个连接而不是特定的某个stream,如果是关联到整个连接,那么stream()方法的返回就是null。

Http2FrameCodec的构造

虽然Http2FrameCodec有构造函数,但是netty推荐使用Http2FrameCodecBuilder来构造它:

Http2FrameCodecBuilder.forServer().build();

可以看到Http2FrameCodecBuilder有一个forServer还有一个forClient方法。他们一个是使用在服务器端,一个是使用在客户端。

主要是通过里面的server属性来进行区分。

Stream的生命周期

frame codec将会向有效的stream发送和写入frames。之前讲过了 Http2StreamFrame 是和一个Http2FrameStream对象相关联的。

对于一个有效的stream来说,如果任意一方发送一个RST_STREAM frame,那么该stream就会被关闭。

或者发送方或者接收方任意一方发送的frame中带有END_STREAM标记,该stream也会被关闭。

流控制

Http2FrameCodec提供了对流的自动控制,但是我们仍然需要做一些操作,来对window进行更新。

具体而言,当我们在接收到Http2DataFrame消息的时候,对消息进行处理之后,需要增大window的大小,表示该data已经被处理了,可以有更多的空间去容纳新的数据。

也就是说需要向ctx中写入一个Http2WindowUpdateFrame,在这个Http2WindowUpdateFrame中需要传入处理的data的大小和对应stream的id,下面是一个处理data frame的例子:

    /**
* 处理data frame消息
*/
private static void onDataRead(ChannelHandlerContext ctx, Http2DataFrame data){
Http2FrameStream stream = data.stream();
if (data.isEndStream()) {
sendResponse(ctx, stream, data.content());
} else {
// 不是end stream不发送,但是需要释放引用
data.release();
}
// 处理完data,需要更新window frame,增加处理过的Data大小
ctx.write(new DefaultHttp2WindowUpdateFrame(data.initialFlowControlledBytes()).stream(stream));
}

上的例子中,我们向DefaultHttp2WindowUpdateFrame传入了对应的stream id,如果stream id为0,则表示处理的是整个connection,而不是单独的某个stream。

除了window update frame之外,对于某个特定stream的初始window还可以发送一个 Http2SettingsFrame,通过设置Http2Settings.initialWindowSize() 达到初始化的目的。

接收消息

对于每个HTTP/2 stream来说,其中包含的frame可以分为 Http2HeadersFrame和Http2DataFrame,而Http2HeadersFrame必定是第一个接收到的frame,并且这个headerFrame还关联了对应的stream对象:Http2FrameStream。

所以我们在处理的时候可以针对这两种不同的frame分别进行处理:

    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
if (msg instanceof Http2HeadersFrame) {
onHeadersRead(ctx, (Http2HeadersFrame) msg);
} else if (msg instanceof Http2DataFrame) {
onDataRead(ctx, (Http2DataFrame) msg);
} else {
super.channelRead(ctx, msg);
}
}

自定义handler

如果使用Http2FrameCodec,我们只需要在pipline中添加Http2FrameCodec之后,再添加自定义的handler即可:

ctx.pipeline().addLast(Http2FrameCodecBuilder.forServer().build(), new CustHttp2Handler());

因为Http2FrameCodec已经对http2中的frame进行了转换,所以我们在CustHttp2Handler中只需要处理自定义逻辑即可。

netty推荐自定义的handler继承自Http2ChannelDuplexHandler,因为它比普通的ChannelDuplexHandler多了一个创建newStream()和遍历所有有效stream的 forEachActiveStream(Http2FrameStreamVisitor)方法。

总结

本文讲解了Http2FrameCodec的原理,和与其搭配的handler实现中要注意的事项。

本文的例子可以参考:learn-netty4

本文已收录于 http://www.flydean.com/31-netty-framecodec-http2/

最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧等你来发现!

欢迎关注我的公众号:「程序那些事」,懂技术,更懂你!

还有这种好事!netty自带http2的编码解码器framecodec的更多相关文章

  1. netty系列之:使用netty实现支持http2的服务器

    目录 简介 基本流程 CleartextHttp2ServerUpgradeHandler Http2ConnectionHandler 总结 简介 上一篇文章中,我们提到了如何在netty中配置TL ...

  2. Netty自带连接池的使用

    一.类介绍1.ChannelPool——连接池接口 2.SimpleChannelPool——实现ChannelPool接口,简单的连接池实现 3.FixedChannelPool——继承Simple ...

  3. netty系列之:netty中常用的字符串编码解码器

    目录 简介 netty中的字符串编码解码器 不同平台的换行符 字符串编码的实现 总结 简介 字符串是我们程序中最常用到的消息格式,也是最简单的消息格式,但是正因为字符串string太过简单,不能附加更 ...

  4. netty系列之:netty中的懒人编码解码器

    目录 简介 netty中的内置编码器 使用codec要注意的问题 netty内置的基本codec base64 bytes compression json marshalling protobuf ...

  5. netty系列之:netty中常用的对象编码解码器

    目录 简介 什么是序列化 重构序列化对象 序列化不是加密 使用真正的加密 使用代理 Serializable和Externalizable的区别 netty中对象的传输 ObjectEncoder O ...

  6. netty系列之:netty中常用的xml编码解码器

    目录 简介 XmlFrameDecoder XmlDecoder 总结 简介 在json之前,xml是最常用的数据传输格式,虽然xml的冗余数据有点多,但是xml的结构简单清晰,至今仍然运用在程序中的 ...

  7. netty系列之:来,手把手教你使用netty搭建一个DNS tcp服务器

    目录 简介 搭建netty服务器 DNS服务器的消息处理 DNS客户端消息请求 总结 简介 在前面的文章中,我们提到了使用netty构建tcp和udp的客户端向已经公布的DNS服务器进行域名请求服务. ...

  8. netty系列之:搭建客户端使用http1.1的方式连接http2服务器

    目录 简介 使用http1.1的方式处理http2 处理TLS连接 处理h2c消息 发送消息 总结 简介 对于http2协议来说,它的底层跟http1.1是完全不同的,但是为了兼容http1.1协议, ...

  9. netty系列之:手持framecodec神器,创建多路复用http2客户端

    目录 简介 配置SslContext 客户端的handler 使用Http2FrameCodec Http2MultiplexHandler和Http2MultiplexCodec 使用子channe ...

随机推荐

  1. Vue3学习(三)之网站首页布局开发

    一.前言 上篇文章已经提到集成Ant Design Vue后,和Element Ui一样,还是组件的使用,然后就是复制粘贴改了. 二.实际案例 先搞个布局布局看看,也就是我们说的layout,如下图: ...

  2. Mybatis一级缓存的锅

    问题背景 项目开发中有一个树形数据结构,不像经典组织结构树.菜单级别树,我们这个树形结构是用户后期手动建立起来的关系.因此数据库表结构为两张表:数据记录表.记录关系表,通过业务规则限制,形成的树形结构 ...

  3. PAT (Basic Level) Practice (中文)1026 程序运行时间 (15分)

    1026 程序运行时间 (15分) 要获得一个 C 语言程序的运行时间,常用的方法是调用头文件 time.h,其中提供了 clock() 函数,可以捕捉从程序开始运行到 clock() 被调用时所耗费 ...

  4. Frida高级逆向-Hook Native(Java So)2

    Frida Hook So 一些操作说明 Native方法第一个参数是 JNIEnv *env 如何在Frida中获取 JNIEnv 对象呢? Java.vm.getEnv(); 如何将string类 ...

  5. Java(29)集合四Collections

    作者:季沐测试笔记 原文地址:https://www.cnblogs.com/testero/p/15228439.html 博客主页:https://www.cnblogs.com/testero ...

  6. (半课内)信安数基 RSA-OAEP 初探

    在RSA攻击中,存在着"小明文攻击"的方式: 在明文够小时,密文也够小,直接开e次方即可: 在明文有点小时,如果e也较小,可用pow(m,e)=n*k+c穷举k尝试爆破 所以,比如 ...

  7. JDBC:(java database Connection) java数据库连接。

    JDBC 指 Java 数据库连接,是一种标准Java应用编程接口( JAVA API),用来连接 Java 编程语言和广泛的数据库. JDBC连接步骤: 1.先导入jar包,把jar放入到工程下并 ...

  8. WPF 排版基础

    一.WPF 排版基础 WPF使用控制面板来进行排版,控制面板实际上是一种可以放入WPF界面元素的容器.当用户把界面元素放入控制面板后,WPF会自动把这些界面元素放在它认为合适的地方.WPF开发人员需要 ...

  9. [Beta]the Agiles Scrum Meeting 9

    会议时间:2020.5.24 21:00 1.每个人的工作 今天已完成的工作 成员 已完成的工作 issue yjy 撰写技术博客 tq 实现评测机获取评测状态功能 评测部分增加更多评测指标 wjx ...

  10. Noip模拟12 2021.7.12

    T1 interval 亏得昨天晚上改掉了T3并且理解了单调栈,今天一扫这题目就知道要用啥了. 先预处理出以a[i]为最大值的最大左右区间.然后再将a[i]取%!!!是的,要不然会影响单调栈的使用.. ...