美文网首页
Netty Http2 协议序列之--初始化链接

Netty Http2 协议序列之--初始化链接

作者: 绝尘驹 | 来源:发表于2018-07-08 20:46 被阅读0次

    H2

    H2C 是代表运行在ssl安全协议之上,https 升级用该协议标示

    H2c

    h2c 代表运行在名为tcp协议之上,这种时候没有https的链接。

    协议切换

    1 发生初始化http get 请求

    客户端通过http1 发送一个带有如下的header:

    GET / HTTP/1.1
    Connection: Upgrade, HTTP2-Settings
    Upgrade: h2c
    HTTP2-Settings: <base64url encoding of HTTP/2 SETTINGS payload>
    

    服务端如果支持http2,则通过响应吗101 来响应客户端,并在响应头带上upgrade:h2c,客户端解析升级请求的响应,满足如下两个条件认为可以升级成功:

    • status code:101
    • header:upgrade:h2c

    2 Connect Preface

    http2 升级成功后,必须先发送一个24自己的字符串Preface,perface就像一个暗号,如果客户端没有这个Preface,则认为是伪装的,服务端会关闭链接,不和你玩了。

    private void sendPreface(ChannelHandlerContext ctx) throws Exception {
                if (prefaceSent || !ctx.channel().isActive()) {
                    return;
                }
    
                prefaceSent = true;
    
                final boolean isClient = !connection().isServer();
                 //在升级完成后,客户端会发送preface
                if (isClient) {
                    // Clients must send the preface string as the first bytes on the connection.
         ctx.write(connectionPrefaceBuf()).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
                }
                 //客户端和服务端都会发送inital setting frame         
                // Both client and server must send their initial settings.
                encoder.writeSettings(ctx, initialSettings, ctx.newPromise()).addListener(
                        ChannelFutureListener.CLOSE_ON_FAILURE);
               
                if (isClient) {
                    // If this handler is extended by the user and we directly fire the userEvent from this context then
                    // the user will not see the event. We should fire the event starting with this handler so this class
                    // (and extending classes) have a chance to process the event.
                    userEventTriggered(ctx, Http2ConnectionPrefaceAndSettingsFrameWrittenEvent.INSTANCE);
                }
            }
    

    3 Init Setting Frame

    客户端在发送完Preface后,可以立即发生init setting frame,不需要等服务端确认后再发,服务端在升级到http2 协议后,读第一个数据包时先检查Preface,然后检查是否时setting frame,如果不是则报链接错误。

    public void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
               try {
                    //1 检查客户端的Preface,如果时客户端,则直接返回true。
                    //2 检查第一个是否时setting frame,
                   if (ctx.channel().isActive() && readClientPrefaceString(in) && verifyFirstFrameIsSettings(in)) {
                       // After the preface is read, it is time to hand over control to the post initialized decoder.
                       //在读完第一个请求后,会切换byteDecoder,即后面的请求就不校验Preface了,而是直接读frame
                       byteDecoder = new FrameDecoder();
                       byteDecoder.decode(ctx, in, out);
                   }
               } catch (Throwable e) {
                   onError(ctx, false, e);
               }
    }
    

    完整过程如下图所示:

    netty-http2-communition.png

    Http Frame

    http2 所有的数据包都是通过一个一个的Frame 来交互的,也就是http2 交互的最小单位

    Frame length(3) + Type(1) + flag(1) + streamId(4) + body

    多路复用 StreamId

    http2 为了支持多路复用,设计了streamid 这个来区别同一个无链接上的每个不同的请求,streamid 可以自己设置,不设置netty回自动生成

    • 客户端生成的streamid需要满足奇数的条件
    • 服务端生成的streamid需要满足偶数的条件

    客户端streamid 看如下代码:高手是怎么判断奇数的

    public boolean isValidStreamId(int streamId) {
         return streamId > 0 && server == ((streamId & 1) == 0);
    }
    

    客户端server为false,服务端server为true,所以客户端为奇数时,streamId & 1 的结果为1,1不等于0,即 ((streamId & 1) == 0) 为false。

    http2 协议还是蛮复杂的一个协议,打算写一个序列,这是开篇,简单的分析了下http2 的链接升级和初始化原理。

    相关文章

      网友评论

          本文标题:Netty Http2 协议序列之--初始化链接

          本文链接:https://www.haomeiwen.com/subject/rxzouftx.html