Netty结合Protobuf进行编解码的方法

2025-05-29 0 41

一般在使用netty时,数据传输的时候都会选择对传输的数据进行编解码编码后的数据变小, 有利于在有限的带宽下传输更多的数据。

由于java本身序列化的缺点较多(无法跨语言,序列化后的码流太大,序列化的性能太低等),业界主流的编解码框架主要有如下三个:

  1. google的protobuf
  2. facebook的thrift
  3. jboss的marshalling

今天我们简单介绍一下netty结合google的protobuf框架进行数据的编解码

1. 什么是protobuf

protobuf全称是google protocol buffers, 它是谷歌公司开源的一个序列化框架。

它将数据结构以.proto文件进行描述,通过代码生成工具可以生成对应数据结构的pojo对象和protobuf相关的方法和属性。

它的特点如下:

  1. 结构化数据存储格式
  2. 高效的编解码性能
  3. 语言无关、平台无关、扩展性好
  4. 官方支持多个语言(java,c++,python,c#等)

2. 下载安装

protobuf已经托管在github上,可以在页面下载,本案例使用的是v3.6(要下载后缀为-win32.zip的)。

下载后,将压缩包进行解压。这里主要用到bin目录下的protoc.exe。

3. 定义好proto文件

subscribereq.proto

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15
// 区分不同的protobuf版本,必须有

syntax = "proto2";

package netty;

// 生成的目标类的包路径

option java_package = "cn.ddlover.nettystudy.protobuf";

// 生成的目标类的名字

option java_outer_classname = "subscribereqproto";

message subscribereq{

required int32 subreqid = 1;

required string username = 2;

required string productname = 3;

repeated string address = 4;

}

subscriberesp.proto

?

1

2

3

4

5

6

7

8

9

10

11
syntax = "proto2";

package netty;

option java_package = "cn.ddlover.nettystudy.protobuf";

option java_outer_classname = "subscriberespproto";

message subscriberesp{

required int32 subreqid = 1;

required int32 respcode = 2;

required string desc = 3;

}

此时项目结构如下

Netty结合Protobuf进行编解码的方法

重点关注一下两个proto文件的位置,是位于项目的根路径下

4. 分别执行以下命令

d:\\xhb\\protoc-3.6.1-win32\\bin\\protoc.exe –java_out=.\\src\\main\\java subscriberesp.proto

d:\\xhb\\protoc-3.6.1-win32\\bin\\protoc.exe –java_out=.\\src\\main\\java subscribereq.proto

这里需要把protoc.exe的位置换成自己的, –java_out命令设置的是proto文件中java_package指令的父目录。

5. 此时项目结构如下

Netty结合Protobuf进行编解码的方法

下面开始代码方面的开发,

1. 先贴一波maven的配置

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36
<?xml version="1.0" encoding="utf-8"?>

<project xmlns="http://maven.apache.org/pom/4.0.0"

xmlns:xsi="http://www.w3.org/2001/xmlschema-instance"

xsi:schemalocation="http://maven.apache.org/pom/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

<modelversion>4.0.0</modelversion>

<groupid>cn.ddlover</groupid>

<artifactid>nettystudy</artifactid>

<version>1.0-snapshot</version>

<properties>

<java.version>1.8</java.version>

</properties>

<dependencies>

<!-- https://mvnrepository.com/artifact/io.netty/netty-all -->

<dependency>

<groupid>io.netty</groupid>

<artifactid>netty-all</artifactid>

<version>4.1.33.final</version>

</dependency>

<!-- https://mvnrepository.com/artifact/com.google.protobuf/protobuf-java -->

<dependency>

<groupid>com.google.protobuf</groupid>

<artifactid>protobuf-java</artifactid>

<version>3.6.1</version>

</dependency>

<dependency>

<groupid>org.projectlombok</groupid>

<artifactid>lombok</artifactid>

<version>1.18.4</version>

</dependency>

</dependencies>

</project>

2. 这里贴上完整代码的项目结构

Netty结合Protobuf进行编解码的方法

3.subreqserver.java

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58
import cn.ddlover.nettystudy.handler.subreqserverhandler;

import cn.ddlover.nettystudy.protobuf.subscribereqproto;

import io.netty.bootstrap.serverbootstrap;

import io.netty.channel.channelfuture;

import io.netty.channel.channelinitializer;

import io.netty.channel.channeloption;

import io.netty.channel.eventloopgroup;

import io.netty.channel.nio.nioeventloopgroup;

import io.netty.channel.socket.socketchannel;

import io.netty.channel.socket.nio.nioserversocketchannel;

import io.netty.handler.codec.protobuf.protobufdecoder;

import io.netty.handler.codec.protobuf.protobufencoder;

import io.netty.handler.codec.protobuf.protobufvarint32framedecoder;

import io.netty.handler.codec.protobuf.protobufvarint32lengthfieldprepender;

import io.netty.handler.logging.loglevel;

import io.netty.handler.logging.logginghandler;

/**

* protobuf版本图书订购代码

*/

public class subreqserver {

private static final int port = 8080;

public static void main(string[] args) {

bind(port);

}

private static void bind(int port) {

eventloopgroup bossgroup = new nioeventloopgroup();

eventloopgroup workergroup = new nioeventloopgroup();

serverbootstrap b = new serverbootstrap();

try {

b.group(bossgroup, workergroup)

.channel(nioserversocketchannel.class)

.option(channeloption.so_backlog, 100)

.handler(new logginghandler(loglevel.info))

.childhandler(new channelinitializer<socketchannel>() {

@override

protected void initchannel(socketchannel socketchannel) throws exception {

// 半包处理

socketchannel.pipeline().addlast(new protobufvarint32framedecoder());

socketchannel.pipeline().addlast(new protobufdecoder(subscribereqproto.subscribereq.getdefaultinstance()));

socketchannel.pipeline().addlast(new protobufvarint32lengthfieldprepender());

socketchannel.pipeline().addlast(new protobufencoder());

socketchannel.pipeline().addlast(new subreqserverhandler());

}

});

channelfuture future = b.bind(port).sync();

future.channel().closefuture().sync();

} catch (interruptedexception e) {

e.printstacktrace();

}finally {

bossgroup.shutdowngracefully();

workergroup.shutdowngracefully();

}

}

}

4.subreqserverhandler.java

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30
import cn.ddlover.nettystudy.protobuf.subscribereqproto;

import cn.ddlover.nettystudy.protobuf.subscriberespproto;

import io.netty.channel.channelhandlercontext;

import io.netty.channel.channelinboundhandleradapter;

public class subreqserverhandler extends channelinboundhandleradapter {

@override

public void channelread(channelhandlercontext ctx, object msg) throws exception {

subscribereqproto.subscribereq req = (subscribereqproto.subscribereq)msg;

if ("张三".equals(req.getusername())) {

system.out.println("server accept clietn subscribe req : ["+req.tostring()+"]");

ctx.writeandflush(resp(req.getsubreqid()));

}

}

private subscriberespproto.subscriberesp resp(int subreqid) {

subscriberespproto.subscriberesp.builder builder = subscriberespproto.subscriberesp.newbuilder();

builder.setsubreqid(subreqid);

builder.setrespcode(0);

builder.setdesc("netty书籍下单成功,3天后将会送到你的住处");

return builder. build();

}

@override

public void exceptioncaught(channelhandlercontext ctx, throwable cause) throws exception {

cause.printstacktrace();

ctx.close();

}

}

5.subreqclient.java

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51
import cn.ddlover.nettystudy.handler.subreqclienthandler;

import cn.ddlover.nettystudy.protobuf.subscriberespproto;

import io.netty.bootstrap.bootstrap;

import io.netty.channel.channelfuture;

import io.netty.channel.channelinitializer;

import io.netty.channel.channeloption;

import io.netty.channel.eventloopgroup;

import io.netty.channel.nio.nioeventloopgroup;

import io.netty.channel.socket.socketchannel;

import io.netty.channel.socket.nio.niosocketchannel;

import io.netty.handler.codec.protobuf.protobufdecoder;

import io.netty.handler.codec.protobuf.protobufencoder;

import io.netty.handler.codec.protobuf.protobufvarint32framedecoder;

import io.netty.handler.codec.protobuf.protobufvarint32lengthfieldprepender;

public class subreqclient {

private static final string host = "localhost";

private static final int port = 8080;

public static void main(string[] args) {

connect(host, port);

}

private static void connect(string host, int port) {

eventloopgroup group = new nioeventloopgroup();

bootstrap b = new bootstrap();

try {

b.group(group).channel(niosocketchannel.class)

.option(channeloption.tcp_nodelay, true)

.handler(new channelinitializer<socketchannel>() {

@override

protected void initchannel(socketchannel socketchannel) throws exception {

// 半包处理

socketchannel.pipeline().addlast(new protobufvarint32framedecoder());

socketchannel.pipeline().addlast(new protobufdecoder(subscriberespproto.subscriberesp.getdefaultinstance()));

socketchannel.pipeline().addlast(new protobufvarint32lengthfieldprepender());

socketchannel.pipeline().addlast(new protobufencoder());

socketchannel.pipeline().addlast(new subreqclienthandler());

}

});

channelfuture f = b.connect(host, port).sync();

f.channel().closefuture().sync();

} catch (interruptedexception e) {

e.printstacktrace();

}finally {

group.shutdowngracefully();

}

}

}

6.subreqclienthandler.java

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42
import cn.ddlover.nettystudy.protobuf.subscribereqproto;

import io.netty.channel.channelhandlercontext;

import io.netty.channel.channelinboundhandleradapter;

import java.util.arraylist;

import java.util.list;

public class subreqclienthandler extends channelinboundhandleradapter {

@override

public void channelactive(channelhandlercontext ctx) throws exception {

for (int i =0;i<10;i++) {

ctx.write(subreq(i));

}

ctx.flush();

}

private subscribereqproto.subscribereq subreq(int i) {

subscribereqproto.subscribereq.builder builder = subscribereqproto.subscribereq.newbuilder();

builder.setsubreqid(i);

builder.setusername("张三");

builder.setproductname("netty book");

list<string> address = new arraylist<>();

address.add("nanjing yuhuatai");

address.add("beijing liulichang");

address.add("shenzhen hongshulin");

builder.addalladdress(address);

return builder.build();

}

@override

public void channelread(channelhandlercontext ctx, object msg) throws exception {

system.out.println("receive server response : ["+ msg +"]");

}

@override

public void exceptioncaught(channelhandlercontext ctx, throwable cause) throws exception {

cause.printstacktrace();

ctx.close();

}

}

代码部分到此就结束了,然后分别运行subreqserversubreqclient, 就可以发现运行成功了。

这里要注意的事,调用tostring的时候,中文在控制台打印的是字节,而调用对应属性的getter方法的时候,是可以做中文的判断的,显然这里protobuf的tostring没有被修改好呀。

当然,我们也可以发现,netty本身已经封装好了对谷歌的protobuf的支持。netty还是很强大的。

到此这篇关于netty结合protobuf进行编解码的文章就介绍到这了,更多相关netty结合protobuf解码内容请搜索快网idc以前的文章或继续浏览下面的相关文章希望大家以后多多支持快网idc!

原文链接:https://blog.csdn.net/qq_33227649/article/details/86689658

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

快网idc优惠网 建站教程 Netty结合Protobuf进行编解码的方法 https://www.kuaiidc.com/104378.html

相关文章

猜你喜欢
发表评论
暂无评论