简介

在之前的文章中,咱们提到了在netty的客户端通过应用Http2FrameCodec和Http2MultiplexHandler能够反对多路复用,也就是说在一个连贯的channel根底上创立多个子channel,通过子channel来解决不同的stream,从而达到多路复用的目标。

既然客户端能够做到多路复用,同样的服务器端也能够,明天给大家介绍一下如何在netty的服务器端打造一个反对http2协定的多路复用服务器。

多路复用的根底

netty中对于http2多路复用的根底类是Http2FrameCodec、Http2MultiplexHandler和Http2MultiplexCodec。

Http2FrameCodec是将底层的HTTP/2 frames音讯映射成为netty中的Http2Frame对象。

有了Http2Frame对象就能够通过Http2MultiplexHandler对新创建的stream开启不同的channel。

Http2MultiplexCodec是Http2FrameCodec和Http2MultiplexHandler的结合体,然而曾经不再被举荐应用了。

因为Http2FrameCodec继承自Http2ConnectionHandler,而Http2MultiplexHandler继承自Http2ChannelDuplexHandler,所以这两个类能够同时在客户端和服务器端应用。

客户端应用Http2FrameCodecBuilder.forClient().build()来取得Http2FrameCodec,而服务器端通过Http2FrameCodecBuilder.forServer().build()来取得Http2FrameCodec。

多路复用在server端的应用

配置TLS处理器

对于服务器端,同样须要解决TLS和一般clear text两种状况。对于TLS来说,咱们须要自建ProtocolNegotiationHandler继承自ApplicationProtocolNegotiationHandler,而后实现configurePipeline办法,在其中别离解决http2和http1.1的连贯:

    protected void configurePipeline(ChannelHandlerContext ctx, String protocol) {        if (ApplicationProtocolNames.HTTP_2.equals(protocol)) {            //增加多路复用反对            ctx.pipeline().addLast(Http2FrameCodecBuilder.forServer().build());            ctx.pipeline().addLast(new Http2MultiplexHandler(new CustMultiplexHttp2Handler()));            return;        }        if (ApplicationProtocolNames.HTTP_1_1.equals(protocol)) {            ctx.pipeline().addLast(new HttpServerCodec(),                                   new HttpObjectAggregator(MAX_CONTENT_LENGTH),                                   new CustHttp1Handler("ALPN Negotiation"));            return;        }        throw new IllegalStateException("未知协定: " + protocol);    }

首先增加Http2FrameCodec,而后增加Http2MultiplexHandler。因为Http2MultiplexHandler曾经封装了多路复用的细节,所以自定义的handler只须要实现失常的音讯解决逻辑即可。

因为Http2FrameCodec曾经对音讯进行了转换成为HTTP2Frame对象,所以只须要解决具体的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);        }    }

配置clear text upgrade

对于h2c的降级来说,须要向pipline中传入sourceCodec和upgradeHandler两个处理器。

sourceCodec能够间接应用HttpServerCodec。

upgradeHandler能够应用HttpServerUpgradeHandler。

HttpServerUpgradeHandler的构造函数须要传入一个sourceCodec和一个upgradeCodecFactory。

sourceCodec咱们曾经有了,再结构一个upgradeCodecFactory即可:

    private static final UpgradeCodecFactory upgradeCodecFactory = protocol -> {        if (AsciiString.contentEquals(Http2CodecUtil.HTTP_UPGRADE_PROTOCOL_NAME, protocol)) {            return new Http2ServerUpgradeCodec(                    Http2FrameCodecBuilder.forServer().build(),                    new Http2MultiplexHandler(new CustMultiplexHttp2Handler()));        } else {            return null;        }    };

从代码中能够看出,upgradeCodecFactory外部又调用了Http2FrameCodec和Http2MultiplexHandler。这和应用TLS的处理器是统一的。

        final ChannelPipeline p = ch.pipeline();        final HttpServerCodec sourceCodec = new HttpServerCodec();        p.addLast(sourceCodec);        p.addLast(new HttpServerUpgradeHandler(sourceCodec, upgradeCodecFactory));

总结

通过上述形式,就能够创立出反对多路复用的http2 netty服务器了。

本文的例子能够参考:learn-netty4

本文已收录于 http://www.flydean.com/33-netty-multiplex-http2server/

最艰深的解读,最粗浅的干货,最简洁的教程,泛滥你不晓得的小技巧等你来发现!

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