我只是給代碼注入靈魂;java
官方地址: github.com/google/prot…python
高效的編碼方式 Google Protocolgit
咱們在編寫網絡應用程序的時候須要注意codec(編解碼器),由於數據在網絡中傳輸的都是二進制字節碼數據,而咱們拿到的目標數據每每
不是字節碼數據,所以在發送數據時就須要編碼,收到數據時須要解碼
codec 的組成部分有兩個:decoder(解碼器)和encoder(編碼器)。encoder 負責把業務數據轉換成字節碼數據,decoder 負責把字節碼數據轉換成業務數據。
其實Java 的序列化技術就能夠做爲codec 去使用,可是它的硬傷太多:
1. 沒法跨語言,這應該是Java 序列化最致命的問題了。
2. 序列化後的體積太大,是二進制編碼的5 倍多。
3. 序列化性能過低。
因爲Java 序列化技術硬傷太多,所以Netty 自身提供了一些codec,以下所示:
Netty 提供的解碼器:
1. StringDecoder, 對字符串數據進行解碼
2. ObjectDecoder,對Java 對象進行解碼
Netty 提供的編碼器:
1. StringEncoder,對字符串數據進行編碼
2. ObjectEncoder,對Java 對象進行編碼
Netty 自己自帶的ObjectDecoder 和ObjectEncoder 能夠用來實現POJO 對象或各類業務對象的編碼和解碼,但其內部使用的還是Java 序列化技術,因此咱們不建議使用。所以對
於POJO 對象或各類業務對象要實現編碼和解碼,咱們須要更高效更強的技術。
複製代碼
Google 的Protocol(Google出品必然牛x)github
Protocol 是Google 發佈的開源項目,全稱Google Protocol Buffers,特色以下:編程
1, 首先是安裝 2, 使用:windows
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>3.5.1</version>
</dependency>
複製代碼
2.2 定義本身的協議格式服務器
接着是須要按照官方要求的語法定義本身的協議格式。網絡
好比我這裏須要定義一個輸入輸出的報文格式: MessageRequestBase.proto多線程
syntax = "proto3"; // (1)
option java_package = "cn.haoxiaoyong.record.proto.protobuf";//(2)
option java_outer_classname = "MessageRequestBase";//(3)
message MessageRequest {//(4)
string requestId = 1;//(5)
string content = 2;
}
複製代碼
(1): 版本號,protobuf語法有 proto2和proto3兩種,這裏指定 proto3併發
(2): 指定包名
(3): 設置生成的Java類名
(4): 內部類的類名,真正的POJO
(5): 設置類中的屬性,符號後是序號,不是屬性值
注意個文件名MessageRequestBase.proto
必須是 .proto後綴
MessageResponseBase.proto:
syntax = "proto3";
option java_package = "cn.haoxiaoyong.record.proto.protobuf";
option java_outer_classname = "MessageResponseBase";
message MessageResponse {
int32 code = 1;
string content = 2;
string msg = 3;
}
複製代碼
以上同理,其中string
,int32
,是這個字段的類型,更多類型參考官方文檔,基本上java中的數據類型都包含了,其中還包含了枚舉(enum
)類型;
MessageRequestBase.proto
,MessageResponseBase.proto
這兩個文件所在的目錄;protoc --java_out=/tmp MessageRequestBase.proto MessageResponseBase.proto
,生成的 java類就會在 /tmp 文件夾下;固然這個目錄能夠改成其餘的.(若是你是windows電腦就能夠指定在C盤下或者D盤下,看心情。。)Client:
public class ClientHandlerInitilizer extends ChannelInitializer<Channel> {
@Override
protected void initChannel(Channel ch) throws Exception {
ch.pipeline()
// google Protobuf 編解碼
.addLast(new ProtobufDecoder(MessageResponseBase.MessageResponse.getDefaultInstance()))
.addLast(new ProtobufEncoder())
.addLast(new NettyClientHandler());
}
}
複製代碼
上述代碼在編寫客戶端程序時,要向Pipeline 鏈中添加ProtobufEncoder 編碼器對象。
@RequestMapping("/send")
public String send(@RequestBody RestInfo restInfo) {
MessageRequestBase.MessageRequest message = new MessageRequestBase.MessageRequest()
.toBuilder()
.setContent(restInfo.getStr())
.setRequestId(UUID.randomUUID().toString()).build();
//異步執行
nettyClient.sendMsg(message);
return "send ok";
}
複製代碼
上述代碼在往服務器端發送(POJO)時就能夠使用生成的MessageRequestBase類搞定,很是方便。 Server:
public class NettyServerHandlerInitializer extends ChannelInitializer<Channel> {
@Override
protected void initChannel(Channel ch) throws Exception {
ch.pipeline()
.addLast(new ProtobufDecoder(MessageRequestBase.MessageRequest.getDefaultInstance()))
.addLast(new ProtobufEncoder())
.addLast(new NettyServerHandler());
}
}
複製代碼
上述代碼在編寫服務器端程序時,要向Pipeline 鏈中添加ProtobufDecoder 解碼器對象。
稍微注意的是,在構建 ProtobufDecoder 時須要顯式指定解碼器須要解碼成什麼類型。在服務端MessageRequestBase.MessageRequest.getDefaultInstance(),在客戶端MessageResponseBase.MessageResponse.getDefaultInstance()
@Override
protected void channelRead0(ChannelHandlerContext ctx, MessageRequestBase.MessageRequest msg) throws Exception {
if (msg.getContent() != null) {
log.info("收到客戶端的業務消息:{}",msg.toString());
//在這裏作一些業務處理操做。。。
String converter = NettyServerHandler.converter.converterTask(msg);
log.info("server 拿處處理後的返回結果 :{}",converter);
MessageResponseBase.MessageResponse response = MessageResponseBase.MessageResponse.newBuilder()
.setCode(200)
.setContent(converter)
.setMsg("success")
.build();
ctx.writeAndFlush(response);
}
}
複製代碼
上述代碼在服務器端接收數據時,直接就能夠把數據轉換成 pojo 使用,很是方便
結束了嗎...No... (看看了時間已經將近零點了,該睡了,看博客你也不要熬夜,注意身體,加油!)
本文介紹了Netty中使用Protobuf的編碼解碼;下篇文件將介紹使用Protobuf解決粘包拆包;
使用方式
1,啓動:NettyApplication 2,使用postman或者其餘工具請求:
控制檯打印:當前項目:Netty框架--netty編碼解碼(項目中proto包下)
歡迎給個小星星鼓勵一下(記得Star哦,害羞臉)....