netty 系列之: 手持 framecodec 神器, 创建多路复用 http2 客户端
简介
在之前的文章中,我们实现了支持 http2 的 netty 服务器,并且使用支持 http2 的浏览器成功的进行访问。虽然浏览器非常通用,但是有时候我们也需要使用特定的 netty 客户端去和服务器进行通信。
今天我们来探讨一下 netty 客户端对 http2 的支持。
配置 SslContext
虽然 http2 并不强制要求支持 TLS,但是现代浏览器都是需要在 TLS 的环境中开启 http2,所以对于客户端来说,同样需要配置好支持 http2 的 SslContext。客户端和服务器端配置 SslContext 的内容没有太大的区别,唯一的区别就是需要调用 SslContextBuilder.forClient()而不是 forServer()方法来获取 SslContextBuilder,创建 SslContext 的代码如下:
如果使用 SSL,那么 ssl handler 必须是 pipline 中的第一个 handler,所以将 SslContext 加入到 pipline 中的代码如下:
客户端的 handler
使用 Http2FrameCodec
netty 的 channel 默认只能接收 ByteBuf 消息,对于 http2 来说,底层传输的是一个个的 frame,直接操作底层的 frame 对于普通程序员来说并不是特别友好,所以 netty 提供了一个 Http2FrameCodec 来对底层的 http2 frame 进行封装成 Http2Frame 对象,方便程序的处理。
在服务器端我们使用 Http2FrameCodecBuilder.forServer()来创建 Http2FrameCodec,在客户端我们使用 Http2FrameCodecBuilder.forClient()来创建 Http2FrameCodec:
然后将其加入到 pipline 中即可使用:
Http2MultiplexHandler 和 Http2MultiplexCodec
我们知道对于 http2 来说一个 TCP 连接中可以创建多个 stream,每个 stream 又是由多个 frame 来组成的。考虑到多路复用的情况,netty 可以为每一个 stream 创建一个单独的 channel,对于新创建的每个 channel 来说,都可以使用 netty 的 ChannelInboundHandler 来对 channel 的消息进行处理,从而提升 netty 处理 http2 的效率。
而这个对 stream 创建新 channel 的支持,在 netty 中有两个专门的类,他们是 Http2MultiplexHandler 和 Http2MultiplexCodec。
他们的功能是一样的,Http2MultiplexHandler 继承自 Http2ChannelDuplexHandler,它必须和 Http2FrameCodec 一起使用。而 Http2MultiplexCodec 本身就是继承自 Http2FrameCodec,已经结合了 Http2FrameCodec 的功能。
但是通过检查源代码,我们发现 Http2MultiplexCodec 是不推荐使用的 API,所以这里我们主要介绍 Http2MultiplexHandler。
对于 Http2MultiplexHandler 来说,每次新创建一个 stream,都会创建一个新的对应的 channel,应用程序使用这个新创建的 channel 来发送和接收 Http2StreamFrame。
新创建的子 channel 会被注册到 netty 的 EventLoop 中,所以对于一个有效的子 channel 来说,并不是立刻就会被匹配到 HTTP/2 stream 上去,而是当第一个 Http2HeadersFrame 成功被发送或者接收之后,才会触发 Event 事件,进而进行绑定操作。
因为是子 channel,所以对于 connection level 的事件,比如 Http2SettingsFrame 和 Http2GoAwayFrame 会首先被父 channel 进行处理,然后再广播到子 channel 中进行处理。
同时,虽然 Http2GoAwayFrame 和 Http2ResetFrame 表示远程节点已经不再接收新的 frame 了,但是因为 channel 本身还可能有 queue 的消息,所以需要等待 Channel.read()为空之后,才会进行关闭操作。
另外对于子 channel 来说,因为不能知道 connection-level 流控制 window,所以如果有溢出的消息会被缓存在父 channel 的 buff 中。
有了 Http2MultiplexHandler,将其加入 client 的 pipline 就可以让客户端支持多路的 channel 了:
使用子 channel 发送消息
从上面的介绍我们知道,一旦使用了 Http2MultiplexHandler,那么具体的消息处理就是在子 channel 中了。那么怎么才能从父 channel 中获取子 channel,然后使用子 channel 来发送信息呢?
netty 提供 Http2StreamChannelBootstrap 类,它提供了 open 方法,来创建子 channel:
我们要做的就是调用这个方法,来创建子 channel:
然后将自定义的,专门处理 Http2StreamFrame 的 Http2ClientStreamFrameHandler,添加到子 channel 的 pipline 中即可:
准备完毕,构建 http2 消息,使用 streamChannel 进行发送:
总结
以上就是使用 netty 的 framecode 构建 http2 的客户端和服务器端进行通信的基本操作了。
本文的例子可以参考:learn-netty4
本文已收录于 http://www.flydean.com/32-netty-http2client-framecodec/
最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧等你来发现!
欢迎关注我的公众号:「程序那些事」,懂技术,更懂你!
版权声明: 本文为 InfoQ 作者【程序那些事】的原创文章。
原文链接:【http://xie.infoq.cn/article/92401f0d041884ea2fb554b29】。文章转载请联系作者。
评论