日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

netty系列之:在netty中使用protobuf协议

發(fā)布時(shí)間:2024/2/28 编程问答 17 豆豆
生活随笔 收集整理的這篇文章主要介紹了 netty系列之:在netty中使用protobuf协议 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

文章目錄

  • 簡介
  • 定義protobuf
  • 定義handler
  • 設(shè)置ChannelPipeline
  • 構(gòu)建client和server端并運(yùn)行
  • 總結(jié)

簡介

netty中有很多適配不同協(xié)議的編碼工具,對(duì)于流行的google出品的protobuf也不例外。netty為其提供了ProtobufDecoder和ProtobufEncoder兩個(gè)工具還有對(duì)應(yīng)的frame detection,接下來我們會(huì)通過一個(gè)例子來詳細(xì)講解如何在netty中使用protobuf。

定義protobuf

我們舉個(gè)最簡單的例子,首先定義一個(gè)需要在網(wǎng)絡(luò)中進(jìn)行傳輸?shù)膍essage,這里我們定義一個(gè)student對(duì)象,他有一個(gè)age和一個(gè)name屬性,如下所示:

syntax = "proto3";package com.flydean17.protobuf;option java_multiple_files = true; option java_package = "com.flydean17.protobuf"; option java_outer_classname = "StudentWrapper";message Student {optional int32 age = 1;optional string name =2; }

使用下面的命令,對(duì)其進(jìn)行編譯:

protoc --experimental_allow_proto3_optional -I=. --java_out=. student.proto

可以看到生成了3個(gè)文件,分別是Student,StudentOrBuilder和StudentWrapper。其中Student和StudentOrBuilder是我們真正需要用到的對(duì)象。

定義handler

在handler中,我們主要進(jìn)行對(duì)消息進(jìn)行處理,這里我們?cè)赾lientHandler中進(jìn)行消息的構(gòu)建和發(fā)送,StudentClientHandler繼承SimpleChannelInboundHandler并重新channelActive方法, 在該方法中我們使用protobuf的語法,構(gòu)建一個(gè)新的Student實(shí)例,并給他設(shè)置好age和name兩個(gè)屬性。

然后使用ctx.write和ctx.flush方法將其發(fā)送到server端:

public void channelActive(ChannelHandlerContext ctx) throws Exception {// channel活躍//構(gòu)建一個(gè)Student,并將其寫入到channel中Student student= Student.newBuilder().setAge(22).setName("flydean").build();log.info("client發(fā)送消息{}",student);ctx.write(student);ctx.flush();}

StudentServerHandler也是繼承SimpleChannelInboundHandler,并重寫channelRead0方法,當(dāng)server端讀取到student消息的時(shí)候,日志輸出,并將其回寫到channel中,供clientHandler讀取:

public void channelRead0(ChannelHandlerContext ctx, Student student) throws Exception {log.info("server收到消息{}",student);// 寫入消息ChannelFuture future = ctx.write(student);}

當(dāng)client讀取到消息之后,直接日志輸出,不再做進(jìn)一步處理,到此,一輪client和server端的交互就完成了:

public void channelRead0(ChannelHandlerContext ctx, Student student) throws Exception {log.info("client收到消息{}",student);}

設(shè)置ChannelPipeline

在上一節(jié),不管是在StudentClientHandler還是在StudentServerHandler中,我們都假設(shè)channel中傳遞的對(duì)象就是Student,而不是原始的ByteBuf。這是怎么做到的呢?

這里我們需要使用到netty提供的frame detection,netty為protobuf協(xié)議專門提供了ProtobufDecoder和ProtobufEncoder,用于對(duì)protobuf對(duì)象進(jìn)行編碼和解碼。

但是這兩個(gè)編碼和解碼器分別是MessageToMessageEncoder和MessageToMessageDecoder,他們是消息到消息的編碼和解碼器,所以還需要和frame detection配合使用。

netty同樣提供了和protobuf配合使用的frame detector,他們是ProtobufVarint32FrameDecoder和ProtobufVarint32LengthFieldPrepender。

Varint32指的是protobuf的編碼格式,第一個(gè)字節(jié)使用的是可變的varint。

有了frame detector和編碼解碼器,我們只需要將其順序加入ChannelPipeline即可。

在客戶端,StudentClientInitializer繼承自ChannelInitializer,我們需要重寫其initChannel方法:

public void initChannel(SocketChannel ch) {ChannelPipeline p = ch.pipeline();p.addLast(new ProtobufVarint32FrameDecoder());p.addLast(new ProtobufDecoder(Student.getDefaultInstance()));p.addLast(new ProtobufVarint32LengthFieldPrepender());p.addLast(new ProtobufEncoder());p.addLast(new StudentClientHandler());}

在服務(wù)器端,同樣StudentServerInitializer也繼承自ChannelInitializer,也需要重寫其initChannel方法:

public void initChannel(SocketChannel ch) throws Exception {ChannelPipeline p = ch.pipeline();p.addLast(new ProtobufVarint32FrameDecoder());p.addLast(new ProtobufDecoder(Student.getDefaultInstance()));p.addLast(new ProtobufVarint32LengthFieldPrepender());p.addLast(new ProtobufEncoder());p.addLast(new StudentServerHandler());}

這樣ChannelPipeline也設(shè)置完成了。

構(gòu)建client和server端并運(yùn)行

最后好做的就是構(gòu)建client和server端并運(yùn)行,這和普通的netty客戶端和服務(wù)器端并沒有什么區(qū)別:

構(gòu)建StudentClient:

public static void main(String[] args) throws Exception {EventLoopGroup group = new NioEventLoopGroup();try {Bootstrap b = new Bootstrap();b.group(group).channel(NioSocketChannel.class).handler(new StudentClientInitializer());// 建立連接Channel ch = b.connect(HOST, PORT).sync().channel();// 等待關(guān)閉ch.closeFuture().sync();} finally {group.shutdownGracefully();}}

構(gòu)建StudentServer:

public static void main(String[] args) throws Exception {EventLoopGroup bossGroup = new NioEventLoopGroup(1);EventLoopGroup workerGroup = new NioEventLoopGroup();try {ServerBootstrap b = new ServerBootstrap();b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).handler(new LoggingHandler(LogLevel.INFO)).childHandler(new StudentServerInitializer());b.bind(PORT).sync().channel().closeFuture().sync();} finally {bossGroup.shutdownGracefully();workerGroup.shutdownGracefully();}}

運(yùn)行可得:

server端: [nioEventLoopGroup-3-1] INFO c.f.protobuf.StudentServerHandler - server收到消息age: 22 name: "flydean"[nioEventLoopGroup-2-1] INFO c.f.protobuf.StudentClientHandler - client發(fā)送消息age: 22 name: "flydean"client端: [nioEventLoopGroup-2-1] INFO c.f.protobuf.StudentClientHandler - client收到消息age: 22 name: "flydean"

可見Student消息已經(jīng)發(fā)送和接收成功了。

總結(jié)

netty提供了很多和協(xié)議適配的工具類,這樣我們就可以專注于業(yè)務(wù)邏輯,不需要考慮具體的編碼轉(zhuǎn)換的問題,非常好用。

本文的例子可以參考:learn-netty4

本文已收錄于 http://www.flydean.com/17-netty-protobuf/

最通俗的解讀,最深刻的干貨,最簡潔的教程,眾多你不知道的小技巧等你來發(fā)現(xiàn)!

歡迎關(guān)注我的公眾號(hào):「程序那些事」,懂技術(shù),更懂你!

總結(jié)

以上是生活随笔為你收集整理的netty系列之:在netty中使用protobuf协议的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。