目錄
簡介
配置SslContext
用戶端的handler
使用Http2FrameCodec
Http2MultiplexHandler和Http2MultiplexCodec
使用子channel發送消息
總結
在之前的文章中,我們實作了支援http2的netty伺服器,并且使用支援http2的浏覽器成功的進行通路。雖然浏覽器非常通用,但是有時候我們也需要使用特定的netty用戶端去和伺服器進行通信。
今天我們來探讨一下netty用戶端對http2的支援。
雖然http2并不強制要求支援TLS,但是現代浏覽器都是需要在TLS的環境中開啟http2,是以對于用戶端來說,同樣需要配置好支援http2的SslContext。用戶端和伺服器端配置SslContext的内容沒有太大的差別,唯一的差別就是需要調用SslContextBuilder.forClient()而不是forServer()方法來擷取SslContextBuilder,建立SslContext的代碼如下:
如果使用SSL,那麼ssl handler必須是pipline中的第一個handler,是以将SslContext加入到pipline中的代碼如下:
netty的channel預設隻能接收ByteBuf消息,對于http2來說,底層傳輸的是一個個的frame,直接操作底層的frame對于普通程式員來說并不是特别友好,是以netty提供了一個Http2FrameCodec來對底層的http2 frame進行封裝成Http2Frame對象,友善程式的處理。
在伺服器端我們使用Http2FrameCodecBuilder.forServer()來建立Http2FrameCodec,在用戶端我們使用Http2FrameCodecBuilder.forClient()來建立Http2FrameCodec:
然後将其加入到pipline中即可使用:
我們知道對于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了:
從上面的介紹我們知道,一旦使用了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/ 最通俗的解讀,最深刻的幹貨,最簡潔的教程,衆多你不知道的小技巧等你來發現! 歡迎關注我的公衆号:「程式那些事」,懂技術,更懂你!