詳解Netty編碼器和解碼器
一、java的編解碼
1.編碼(Encode)稱為序列化, 它將對象序列化為字節(jié)數組,用于網絡傳輸、數據持久化或者其它 用途。
2.解碼(Decode)稱為反序列化,它把從網絡、磁盤等讀取的字節(jié)數組還原成原始對象(通常是原 始對象的拷貝),以方便后續(xù)的業(yè)務邏輯操作。
java序列化對象只需要實現java.io.Serializable接口并生成序列化ID,這個類就能夠通過 java.io.ObjectInput和java.io.ObjectOutput序列化和反序列化。
java序列化對象只需要實現java.io.Serializable接口并生成序列化ID,這個類就能夠通過 java.io.ObjectInput和java.io.ObjectOutput序列化和反序列化。
Java序列化目的:1.網絡傳輸。2.對象持久化。
Java序列化缺點:1.無法跨語言。 2.序列化后碼流太大。3.序列化性能太低。
Java序列化僅僅是Java編解碼技術的一種,由于它的種種缺陷,衍生出了多種編解碼技術和框 架,這些編解碼框架實現消息的高效序列化。
二、Netty編解碼器
概念:在網絡應用中需要實現某種編解碼器,將原始字節(jié)數據與自定義的消息對象進行互相轉換。網絡中都是以字節(jié)碼的數據形式來傳輸數據的,服務器編碼數據后發(fā)送到客戶端,客戶端需要對數據進行解碼。
對于Netty而言,編解碼器由兩部分組成:編碼器、解碼器
- 解碼器:負責將消息從字節(jié)或其他序列形式轉成指定的消息對象。
- 編碼器:將消息對象轉成字節(jié)或其他序列形式在網絡上傳輸。
Netty 的編(解)碼器實現了 ChannelHandlerAdapter,也是一種特殊的 ChannelHandler,所 以依賴于 ChannelPipeline,可以將多個編(解)碼器鏈接在一起,以實現復雜的轉換邏輯。
Netty里面的編解碼: 解碼器:負責處理“入站 InboundHandler”數據。 編碼器:負責“出站 OutboundHandler” 數據。
入棧解碼,出棧編碼:
2.1 解碼器(Decoder)
解碼器負責 解碼“入站”數據從一種格式到另一種格式,解碼器處理入站數據是抽象 ChannelInboundHandler的實現。需要將解碼器放在ChannelPipeline中。對于解碼器,Netty中主要提供了抽象基類ByteToMessageDecoder和MessageToMessageDecoder。
抽象解碼器
ByteToMessageDecoder: 用于將字節(jié)轉為消息,需要檢查緩沖區(qū)是否有足夠的字節(jié)
ReplayingDecoder: 繼承ByteToMessageDecoder,不需要檢查緩沖區(qū)是否有足夠的字節(jié),但 是 ReplayingDecoder速度略慢于ByteToMessageDecoder,同時不是所有的ByteBuf都支持。 項目復雜性高則使用ReplayingDecoder,否則使用ByteToMessageDecoder
MessageToMessageDecoder: 用于從一種消息解碼為另外一種消息(例如POJO到POJO)
核心方法
decode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out)
2.2 代碼實現
MessageDecoder
package com.my.codec; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.MessageToMessageDecoder; import io.netty.util.CharsetUtil; import java.util.List; /** * 消息解碼器 */ public class MessageDecoder extends MessageToMessageDecoder { @Override protected void decode(ChannelHandlerContext ctx, Object msg, List out) throws Exception { System.out.println("正在進行消息解碼...."); ByteBuf byteBuf = (ByteBuf) msg; out.add(byteBuf.toString(CharsetUtil.UTF_8));//傳遞到下一個handler } }
NettyServerHandler
nettyServerHandler 實現ChannelInboundHandler, 重新若干方法。
通道讀取方法:
/** * 通道讀取事件 * * @param ctx * @param msg * @throws Exception */ @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { System.out.println("客戶端發(fā)送過來的消息:" + msg); }
服務端在接收客戶端的消息時,首先會經過MessageDecoder編碼器,將字節(jié)變?yōu)樽址?,因此,在此處可直接輸出?/p>
NettyServer
serverBootstrap.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .option(ChannelOption.SO_BACKLOG, 128) .childOption(ChannelOption.SO_KEEPALIVE, Boolean.TRUE) .childHandler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { //添加解碼器 ch.pipeline().addLast("messageDecoder", new MessageDecoder()); //向pipeline中添加自定義業(yè)務處理handler ch.pipeline().addLast(new NettyServerHandler()); } });
在pipeline中添加解碼器
2.3 編碼器(Encoder)
與ByteToMessageDecoder和MessageToMessageDecoder相對應,Netty提供了對應的編碼器 實現MessageToByteEncoder和MessageToMessageEncoder,二者都實現 ChannelOutboundHandler接口。
抽象編碼器
MessageToByteEncoder: 將消息轉化成字節(jié)MessageToMessageEncoder: 用于從一種消息編碼為另外一種消息(例如POJO到POJO)
核心方法:
encode(ChannelHandlerContext ctx, String msg, List<Object> out)
2.4 代碼實現
MessageEncoder
package com.my.codec; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.MessageToMessageEncoder; import io.netty.util.CharsetUtil; import java.util.List; /** * 消息的編碼器 */ public class MessageEncoder extends MessageToMessageEncoder { @Override protected void encode(ChannelHandlerContext ctx, Object msg, List out) throws Exception { System.out.println("消息正在進行編碼...."); String str = (String) msg; out.add(Unpooled.copiedBuffer(str, CharsetUtil.UTF_8)); } }
NettyClientHandler
/** * 通道就緒事件 * * @param ctx * @throws Exception */ @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { ChannelFuture future = ctx.writeAndFlush("你好呀.我是Netty客戶端"); future.addListener(new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture future) throws Exception { if (future.isSuccess()) { System.out.println("數據發(fā)送成功!"); } else { System.out.println("數據發(fā)送失敗!"); } } }); } /** * 通道讀就緒事件 * * @param ctx * @param msg * @throws Exception */ @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { System.out.println("服務端發(fā)送的消息:" + msg); }
當客戶端通道準備就緒時,會向服務端發(fā)送 “你好呀.我是Netty客戶端”,由于出棧是逆序的,因此,直接傳入字符串,當出棧時,會經過編碼器(在nettyclient中添加的)
NettyClient
bootstrap.group(group) .channel(NioSocketChannel.class) .handler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { //添加解碼器 ch.pipeline().addLast("messageDecoder", new MessageDecoder()); //添加編碼器 ch.pipeline().addLast("messageEncoder", new MessageEncoder()); //向pipeline中添加自定義業(yè)務處理handler ch.pipeline().addLast(new NettyClientHandler()); } });
同時,在NettyServerHandler 中也添加相同的編解碼器。
因為是雙向通信,因此,在服務端和客戶端的pipeline中均需要添加編解碼器。
2.5 測試結果
服務端打印:
客戶端打?。?/p>
三、編碼解碼器Codec
編碼解碼器:
同時具有編碼與解碼功能,特點同時實現了ChannelInboundHandler和 ChannelOutboundHandler接口,因此在數據輸入和輸出時都能進行處理。
Netty提供提供了一個ChannelDuplexHandler適配器類,編碼解碼器的抽象基類
ByteToMessageCodec ,MessageToMessageCodec都繼承與此類
3.1 代碼實現:
package com.my.codec; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.MessageToMessageCodec; import io.netty.util.CharsetUtil; import java.util.List; /** * 消息編解碼器 */ public class MessageCodec extends MessageToMessageCodec { /** * 編碼 * * @param ctx * @param msg * @param out * @throws Exception */ @Override protected void encode(ChannelHandlerContext ctx, Object msg, List out) throws Exception { System.out.println("消息正在進行編碼...."); String str = (String) msg; out.add(Unpooled.copiedBuffer(str, CharsetUtil.UTF_8)); } /** * 解碼 * * @param ctx * @param msg * @param out * @throws Exception */ @Override protected void decode(ChannelHandlerContext ctx, Object msg, List out) throws Exception { System.out.println("正在進行消息解碼...."); ByteBuf byteBuf = (ByteBuf) msg; out.add(byteBuf.toString(CharsetUtil.UTF_8));//傳遞到下一個handler } }
NettyServer、NettyClient
在NettyServer和NettyClient中添加
ch.pipeline().addLast(new MessageCodec()); //8. 向pipeline中添加自定義業(yè)務處理handler ch.pipeline().addLast(new NettyServerHandler());
eBuf = (ByteBuf) msg;
out.add(byteBuf.toString(CharsetUtil.UTF_8));//傳遞到下一個handler
}
}
ch.pipeline().addLast(new MessageCodec()); //8. 向pipeline中添加自定義業(yè)務處理handler ch.pipeline().addLast(new NettyServerHandler());
測試結果與1.2.5測試結果一致
到此這篇關于詳解Netty編碼器和解碼器的文章就介紹到這了,更多相關Netty編解碼器內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Spring Boot實戰(zhàn)之靜態(tài)資源處理
這篇文章主要介紹了Spring Boot實戰(zhàn)之靜態(tài)資源處理,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-01-01基于Springboot的高校社團管理系統(tǒng)的設計與實現
本文將基于Springboot+Mybatis開發(fā)實現一個高校社團管理系統(tǒng),系統(tǒng)包含三個角色:管理員、團長、會員。文中采用的技術有Springboot、Mybatis、Jquery、AjAX、JSP等,感興趣的可以了解一下2022-07-07徹底解決java.lang.ClassNotFoundException: com.mysql.jdbc.Dr
這篇文章給大家介紹了如如何徹底解決java.lang.ClassNotFoundException: com.mysql.jdbc.Driver問題,文中有詳細的解決思路以及解決方法,需要的朋友可以參考下2023-11-11Spring Gateway處理微服務的路由轉發(fā)機制
我們詳細地介紹了Spring Gateway,這個基于Spring 5、Spring Boot 2和Project Reactor的API網關,通過這篇文章,我們可以清晰地看到Spring Gateway的工作原理,以及它的強大之處,感興趣的朋友一起看看吧2024-08-08