詳解Netty編碼器和解碼器
一、java的編解碼
1.編碼(Encode)稱為序列化, 它將對象序列化為字節(jié)數(shù)組,用于網(wǎng)絡(luò)傳輸、數(shù)據(jù)持久化或者其它 用途。
2.解碼(Decode)稱為反序列化,它把從網(wǎng)絡(luò)、磁盤等讀取的字節(jié)數(shù)組還原成原始對象(通常是原 始對象的拷貝),以方便后續(xù)的業(yè)務(wù)邏輯操作。

java序列化對象只需要實現(xiàn)java.io.Serializable接口并生成序列化ID,這個類就能夠通過 java.io.ObjectInput和java.io.ObjectOutput序列化和反序列化。
java序列化對象只需要實現(xiàn)java.io.Serializable接口并生成序列化ID,這個類就能夠通過 java.io.ObjectInput和java.io.ObjectOutput序列化和反序列化。
Java序列化目的:1.網(wǎng)絡(luò)傳輸。2.對象持久化。
Java序列化缺點:1.無法跨語言。 2.序列化后碼流太大。3.序列化性能太低。
Java序列化僅僅是Java編解碼技術(shù)的一種,由于它的種種缺陷,衍生出了多種編解碼技術(shù)和框 架,這些編解碼框架實現(xiàn)消息的高效序列化。
二、Netty編解碼器
概念:在網(wǎng)絡(luò)應(yīng)用中需要實現(xiàn)某種編解碼器,將原始字節(jié)數(shù)據(jù)與自定義的消息對象進行互相轉(zhuǎn)換。網(wǎng)絡(luò)中都是以字節(jié)碼的數(shù)據(jù)形式來傳輸數(shù)據(jù)的,服務(wù)器編碼數(shù)據(jù)后發(fā)送到客戶端,客戶端需要對數(shù)據(jù)進行解碼。
對于Netty而言,編解碼器由兩部分組成:編碼器、解碼器
- 解碼器:負責(zé)將消息從字節(jié)或其他序列形式轉(zhuǎn)成指定的消息對象。
- 編碼器:將消息對象轉(zhuǎn)成字節(jié)或其他序列形式在網(wǎng)絡(luò)上傳輸。
Netty 的編(解)碼器實現(xiàn)了 ChannelHandlerAdapter,也是一種特殊的 ChannelHandler,所 以依賴于 ChannelPipeline,可以將多個編(解)碼器鏈接在一起,以實現(xiàn)復(fù)雜的轉(zhuǎn)換邏輯。
Netty里面的編解碼: 解碼器:負責(zé)處理“入站 InboundHandler”數(shù)據(jù)。 編碼器:負責(zé)“出站 OutboundHandler” 數(shù)據(jù)。
入棧解碼,出棧編碼:
2.1 解碼器(Decoder)
解碼器負責(zé) 解碼“入站”數(shù)據(jù)從一種格式到另一種格式,解碼器處理入站數(shù)據(jù)是抽象 ChannelInboundHandler的實現(xiàn)。需要將解碼器放在ChannelPipeline中。對于解碼器,Netty中主要提供了抽象基類ByteToMessageDecoder和MessageToMessageDecoder。

抽象解碼器
ByteToMessageDecoder: 用于將字節(jié)轉(zhuǎn)為消息,需要檢查緩沖區(qū)是否有足夠的字節(jié)
ReplayingDecoder: 繼承ByteToMessageDecoder,不需要檢查緩沖區(qū)是否有足夠的字節(jié),但 是 ReplayingDecoder速度略慢于ByteToMessageDecoder,同時不是所有的ByteBuf都支持。 項目復(fù)雜性高則使用ReplayingDecoder,否則使用ByteToMessageDecoder
MessageToMessageDecoder: 用于從一種消息解碼為另外一種消息(例如POJO到POJO)
核心方法
decode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out)
2.2 代碼實現(xiàn)
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 實現(xiàn)ChannelInboundHandler, 重新若干方法。
通道讀取方法:
/**
* 通道讀取事件
*
* @param ctx
* @param msg
* @throws Exception
*/
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("客戶端發(fā)送過來的消息:" + msg);
}
服務(wù)端在接收客戶端的消息時,首先會經(jīng)過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è)務(wù)處理handler
ch.pipeline().addLast(new NettyServerHandler());
}
});
在pipeline中添加解碼器
2.3 編碼器(Encoder)
與ByteToMessageDecoder和MessageToMessageDecoder相對應(yīng),Netty提供了對應(yīng)的編碼器 實現(xiàn)MessageToByteEncoder和MessageToMessageEncoder,二者都實現(xiàn) ChannelOutboundHandler接口。

抽象編碼器
MessageToByteEncoder: 將消息轉(zhuǎn)化成字節(jié)MessageToMessageEncoder: 用于從一種消息編碼為另外一種消息(例如POJO到POJO)
核心方法:
encode(ChannelHandlerContext ctx, String msg, List<Object> out)
2.4 代碼實現(xiàn)
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("數(shù)據(jù)發(fā)送成功!");
} else {
System.out.println("數(shù)據(jù)發(fā)送失敗!");
}
}
});
}
/**
* 通道讀就緒事件
*
* @param ctx
* @param msg
* @throws Exception
*/
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("服務(wù)端發(fā)送的消息:" + msg);
}
當客戶端通道準備就緒時,會向服務(wù)端發(fā)送 “你好呀.我是Netty客戶端”,由于出棧是逆序的,因此,直接傳入字符串,當出棧時,會經(jīng)過編碼器(在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è)務(wù)處理handler
ch.pipeline().addLast(new NettyClientHandler());
}
});
同時,在NettyServerHandler 中也添加相同的編解碼器。
因為是雙向通信,因此,在服務(wù)端和客戶端的pipeline中均需要添加編解碼器。
2.5 測試結(jié)果
服務(wù)端打印:

客戶端打?。?/p>

三、編碼解碼器Codec
編碼解碼器:
同時具有編碼與解碼功能,特點同時實現(xiàn)了ChannelInboundHandler和 ChannelOutboundHandler接口,因此在數(shù)據(jù)輸入和輸出時都能進行處理。

Netty提供提供了一個ChannelDuplexHandler適配器類,編碼解碼器的抽象基類
ByteToMessageCodec ,MessageToMessageCodec都繼承與此類
3.1 代碼實現(xiàn):
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è)務(wù)處理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è)務(wù)處理handler ch.pipeline().addLast(new NettyServerHandler());
測試結(jié)果與1.2.5測試結(jié)果一致
到此這篇關(guān)于詳解Netty編碼器和解碼器的文章就介紹到這了,更多相關(guān)Netty編解碼器內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring Boot實戰(zhàn)之靜態(tài)資源處理
這篇文章主要介紹了Spring Boot實戰(zhàn)之靜態(tài)資源處理,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-01-01
基于Springboot的高校社團管理系統(tǒng)的設(shè)計與實現(xiàn)
本文將基于Springboot+Mybatis開發(fā)實現(xiàn)一個高校社團管理系統(tǒng),系統(tǒng)包含三個角色:管理員、團長、會員。文中采用的技術(shù)有Springboot、Mybatis、Jquery、AjAX、JSP等,感興趣的可以了解一下2022-07-07
徹底解決java.lang.ClassNotFoundException: com.mysql.jdbc.Dr
這篇文章給大家介紹了如如何徹底解決java.lang.ClassNotFoundException: com.mysql.jdbc.Driver問題,文中有詳細的解決思路以及解決方法,需要的朋友可以參考下2023-11-11
Spring Gateway處理微服務(wù)的路由轉(zhuǎn)發(fā)機制
我們詳細地介紹了Spring Gateway,這個基于Spring 5、Spring Boot 2和Project Reactor的API網(wǎng)關(guān),通過這篇文章,我們可以清晰地看到Spring Gateway的工作原理,以及它的強大之處,感興趣的朋友一起看看吧2024-08-08

