天天看點

由Netty引出對協定的思考協定到底是什麼?

協定到底是什麼?

之前我們接觸過很多協定,最熟悉莫過于HTTP、TCP、DUBBO 那麼到底是什麼是協定,又和Netty、TCP、SOCKET有何關系?

協定:兩端約定好的一種位元組數組結構,

應用層協定:例如前8個位元組表示消息類型 後8個位元組代表總資料的長度,由于現在都是使用面向對象語言程式設計,那麼如何将業務對象資料轉換成網絡傳輸的位元組,已經将位元組反序列化成對象。目前用的比較多方式有json序列化,java的對象序列化,protobuf,hessian,xml形式。 發送資料端按照約定俗成方式編碼,那麼接受端就以同樣方式進行解碼。 這種協定就是應用層協定。

傳輸層協定:tcp協定是可靠、面向封包段的傳輸協定,tcp封包頭+應用層的位元組資料 保證資料傳給某台主機對應的端口号的程序進行處理

網絡層協定:ip頭+tcp封包資料 保證該資料傳給指定ip的主機

資料鍊路層和實體層

下發消息時每經過一層協定就會加上該層的頭部資訊,在接受消息時每經過一層協定就會去掉頭部資訊,最終會在傳輸層被接受,然後通過socket(擷取tcp層資料的工具)拿到資料,然後根據不同的應用層協定(定義的不同位元組結構)進行解析到應用層所有使用的資料(位元組),然後解碼(json、protobuf)成業務對象

Socket可以看作是擷取tcp層資料或向tcp寫入資料的工具

Netty可以看作成socket架構,用該架構可以做自定義協定(通過實作ChannelHandler的編碼器和解碼器)的伺服器和用戶端,同時可以處理高并發的連接配接(非阻塞I/O),面向事件驅動開發(自定義實作ChannelHandler進行監聽Channel的某種事件)

編解碼器

之是以Netty能實作各種應用層協定 例如HTTP、FTP、WebSocket 或自定義的協定,就是編解碼器起到的作用。

編碼器:将業務對象轉換成某種特定格式的位元組數組(例如 頭部+消息體(将對象轉換成位元組稱為序列化(JSON、ProtoBuf、java對象序列化))),進行網絡傳輸

解碼器:接收到網絡傳輸的二進制位元組數組,通過對應的解碼器轉化成業務所使用的對象,隻不過是上面的逆過程

tcp層隻關心傳輸的二進制資料,是以會将應用層的資料劃分成多個封包段,是以通過Netty擷取tcp中的資料可能是拆包的或者粘包的。以下Netty定義的幾種解決此問題的方法:

1、固定長度資料

也就是網絡上傳輸的資料都是統一長度的資料

2、分隔符

通常采用\r\n方式來區分傳輸的資料,當然也可以自定義分隔符

3、頭部+消息體

頭部:一般固定好長度, 存放消息類型,消息體大小

具體消息内容:大小就等于頭部定義的大小

HTTP協定采用 分隔符+頭部、消息體結合的方式傳輸的資料

Netty編解碼實作

由于應用層資料在傳輸層會拆成各個小封包段,還有netty又是異步的,是以在解碼時候需要對接受的資料進行緩存直到解碼成最終需要的結果。

得益于Netty的易擴充性,可以通過增加對應的ChannelHandler實作就能完成某種功能,同樣編解碼器也實作了ChannelInBound和ChannelOutBound接口

編解碼器的基礎實作類,其他都是繼承該基類

抽象模闆設計模式

ByteToMessageDecoder:從位元組轉化業務對象

實作該抽象方法 decode(ChannelHandlerContext ctx, ByteBuf in, List out)

out存放解碼後對象

可能一開始不滿足解碼條件,可以緩存起來,例如需要頭部位元組數為10,也就是可讀位元組數>=10時,才進行解析

MessageToMessageDecoder:從消息對象A解碼成另外一種消息對象B

decode(ChannelHandlerContext ctx, I msg, List out) I:表示輸入對象A 然後解碼成另外一種對象B存放到out中

MessageToByteEncoder:将業務對象轉換成位元組

encode(ChannelHandlerContext ctx, I msg, ByteBuf out) I:就是輸入的業務對象轉換成特定格式的位元組數組對象傳給out

MessageToMessageEncoder:從消息對象B編碼另外一種消息對象A

encode(ChannelHandlerContext ctx, I msg, List out) I:表示輸出對象B 然後解碼成另外一種對象A存放到out中

源碼實習借鑒處

1、将CodecOutputList (也是實作了List接口) 放在ThreadLocal中保證線程安全

2、使用對象池将CodecOutputList緩存起來,避免了重複建立對象開銷和節省記憶體資源

繼續閱讀