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

本文主要是介绍netty系列之:手持framecodec神器,创建多路复用http2客户端,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 简介
  • 配置SslContext
  • 客户端的handler
    • 使用Http2FrameCodec
    • Http2MultiplexHandler和Http2MultiplexCodec
    • 使用子channel发送消息
  • 总结

简介

在之前的文章中,我们实现了支持http2的netty服务器,并且使用支持http2的浏览器成功的进行访问。虽然浏览器非常通用,但是有时候我们也需要使用特定的netty客户端去和服务器进行通信。

今天我们来探讨一下netty客户端对http2的支持。

配置SslContext

虽然http2并不强制要求支持TLS,但是现代浏览器都是需要在TLS的环境中开启http2,所以对于客户端来说,同样需要配置好支持http2的SslContext。客户端和服务器端配置SslContext的内容没有太大的区别,唯一的区别就是需要调用SslContextBuilder.forClient()而不是forServer()方法来获取SslContextBuilder,创建SslContext的代码如下:

SslProvider provider =SslProvider.isAlpnSupported(SslProvider.OPENSSL)? SslProvider.OPENSSL : SslProvider.JDK;sslCtx = SslContextBuilder.forClient().sslProvider(provider).ciphers(Http2SecurityUtil.CIPHERS, SupportedCipherSuiteFilter.INSTANCE)// 因为我们的证书是自生成的,所以需要信任放行.trustManager(InsecureTrustManagerFactory.INSTANCE).applicationProtocolConfig(new ApplicationProtocolConfig(Protocol.ALPN,SelectorFailureBehavior.NO_ADVERTISE,SelectedListenerFailureBehavior.ACCEPT,ApplicationProtocolNames.HTTP_2,ApplicationProtocolNames.HTTP_1_1)).build();

如果使用SSL,那么ssl handler必须是pipline中的第一个handler,所以将SslContext加入到pipline中的代码如下:

ch.pipeline().addFirst(sslCtx.newHandler(ch.alloc()));

客户端的handler

使用Http2FrameCodec

netty的channel默认只能接收ByteBuf消息,对于http2来说,底层传输的是一个个的frame,直接操作底层的frame对于普通程序员来说并不是特别友好,所以netty提供了一个Http2FrameCodec来对底层的http2 frame进行封装成Http2Frame对象,方便程序的处理。

在服务器端我们使用Http2FrameCodecBuilder.forServer()来创建Http2FrameCodec,在客户端我们使用Http2FrameCodecBuilder.forClient()来创建Http2FrameCodec:

Http2FrameCodec http2FrameCodec = Http2FrameCodecBuilder.forClient().initialSettings(Http2Settings.defaultSettings()).build();

然后将其加入到pipline中即可使用:

        ch.pipeline().addLast(http2FrameCodec);

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的功能。

public final class Http2MultiplexHandler extends Http2ChannelDuplexHandler@Deprecated
public class Http2MultiplexCodec extends 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了:

ch.pipeline().addLast(new Http2MultiplexHandler(new SimpleChannelInboundHandler() {@Overrideprotected void channelRead0(ChannelHandlerContext ctx, Object msg) {// 处理inbound streamslog.info("Http2MultiplexHandler接收到消息: {}",msg);}}))

使用子channel发送消息

从上面的介绍我们知道,一旦使用了Http2MultiplexHandler,那么具体的消息处理就是在子channel中了。那么怎么才能从父channel中获取子channel,然后使用子channel来发送信息呢?

netty提供Http2StreamChannelBootstrap类,它提供了open方法,来创建子channel:

        final Http2StreamChannel streamChannel;try {if (ctx.handler() instanceof Http2MultiplexCodec) {streamChannel = ((Http2MultiplexCodec) ctx.handler()).newOutboundStream();} else {streamChannel = ((Http2MultiplexHandler) ctx.handler()).newOutboundStream();}

我们要做的就是调用这个方法,来创建子channel:

final Http2StreamChannel streamChannel = streamChannelBootstrap.open().syncUninterruptibly().getNow();

然后将自定义的,专门处理Http2StreamFrame的Http2ClientStreamFrameHandler,添加到子channel的pipline中即可:

final Http2ClientStreamFrameHandler streamFrameResponseHandler =new Http2ClientStreamFrameHandler();
streamChannel.pipeline().addLast(streamFrameResponseHandler);

准备完毕,构建http2消息,使用streamChannel进行发送:

// 发送HTTP2 get请求final DefaultHttp2Headers headers = new DefaultHttp2Headers();headers.method("GET");headers.path(PATH);headers.scheme(SSL? "https" : "http");Http2HeadersFrame headersFrame = new DefaultHttp2HeadersFrame(headers, true);streamChannel.writeAndFlush(headersFrame);

总结

以上就是使用netty的framecode构建http2的客户端和服务器端进行通信的基本操作了。

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

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

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

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

这篇关于netty系列之:手持framecodec神器,创建多路复用http2客户端的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


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

相关文章

Macos创建python虚拟环境的详细步骤教学

《Macos创建python虚拟环境的详细步骤教学》在macOS上创建Python虚拟环境主要通过Python内置的venv模块实现,也可使用第三方工具如virtualenv,下面小编来和大家简单聊聊... 目录一、使用 python 内置 venv 模块(推荐)二、使用 virtualenv(兼容旧版 P

基于Python+PyQt5打造一个跨平台Emoji表情管理神器

《基于Python+PyQt5打造一个跨平台Emoji表情管理神器》在当今数字化社交时代,Emoji已成为全球通用的视觉语言,本文主要为大家详细介绍了如何使用Python和PyQt5开发一个功能全面的... 目录概述功能特性1. 全量Emoji集合2. 智能搜索系统3. 高效交互设计4. 现代化UI展示效果

Linux lvm实例之如何创建一个专用于MySQL数据存储的LVM卷组

《Linuxlvm实例之如何创建一个专用于MySQL数据存储的LVM卷组》:本文主要介绍使用Linux创建一个专用于MySQL数据存储的LVM卷组的实例,具有很好的参考价值,希望对大家有所帮助,... 目录在Centos 7上创建卷China编程组并配置mysql数据目录1. 检查现有磁盘2. 创建物理卷3. 创

Python+PyQt5实现MySQL数据库备份神器

《Python+PyQt5实现MySQL数据库备份神器》在数据库管理工作中,定期备份是确保数据安全的重要措施,本文将介绍如何使用Python+PyQt5开发一个高颜值,多功能的MySQL数据库备份工具... 目录概述功能特性核心功能矩阵特色功能界面展示主界面设计动态效果演示使用教程环境准备操作流程代码深度解

C#使用MQTTnet实现服务端与客户端的通讯的示例

《C#使用MQTTnet实现服务端与客户端的通讯的示例》本文主要介绍了C#使用MQTTnet实现服务端与客户端的通讯的示例,包括协议特性、连接管理、QoS机制和安全策略,具有一定的参考价值,感兴趣的可... 目录一、MQTT 协议简介二、MQTT 协议核心特性三、MQTTNET 库的核心功能四、服务端(BR

SpringBoot快速搭建TCP服务端和客户端全过程

《SpringBoot快速搭建TCP服务端和客户端全过程》:本文主要介绍SpringBoot快速搭建TCP服务端和客户端全过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,... 目录TCPServerTCPClient总结由于工作需要,研究了SpringBoot搭建TCP通信的过程

Java 如何创建和使用ExecutorService

《Java如何创建和使用ExecutorService》ExecutorService是Java中用来管理和执行多线程任务的一种高级工具,可以有效地管理线程的生命周期和任务的执行过程,特别是在需要处... 目录一、什么是ExecutorService?二、ExecutorService的核心功能三、如何创建

Python+PyQt5开发一个Windows电脑启动项管理神器

《Python+PyQt5开发一个Windows电脑启动项管理神器》:本文主要介绍如何使用PyQt5开发一款颜值与功能并存的Windows启动项管理工具,不仅能查看/删除现有启动项,还能智能添加新... 目录开篇:为什么我们需要启动项管理工具功能全景图核心技术解析1. Windows注册表操作2. 启动文件

使用Python创建一个功能完整的Windows风格计算器程序

《使用Python创建一个功能完整的Windows风格计算器程序》:本文主要介绍如何使用Python和Tkinter创建一个功能完整的Windows风格计算器程序,包括基本运算、高级科学计算(如三... 目录python实现Windows系统计算器程序(含高级功能)1. 使用Tkinter实现基础计算器2.

CentOS和Ubuntu系统使用shell脚本创建用户和设置密码

《CentOS和Ubuntu系统使用shell脚本创建用户和设置密码》在Linux系统中,你可以使用useradd命令来创建新用户,使用echo和chpasswd命令来设置密码,本文写了一个shell... 在linux系统中,你可以使用useradd命令来创建新用户,使用echo和chpasswd命令来设