乐趣区

关于dart:netty系列之性能为王创建多路复用http2服务器

简介

在之前的文章中,咱们提到了在 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/

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

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

退出移动版