深入理解Netty编解码、粘包拆包、心跳机制( 四 )
sudo -i
- 解压压缩包 , 并进入你自己解压的目录
tar xyf protobuf-all-3.13.0.tar.gzcd protobuf-3.13.0
- 设置编译目录
./configure --prefix=/usr/local/protobuf
- 安装
makemake install
- 配置环境变量
cd ~open .bash_profile
第二步:然后在打开的bash_profile文件末尾添加如下配置:export PROTOBUF=/usr/local/protobuf export PATH=$PROTOBUF/bin:$PATH
第三步:source一下使文件生效source .bash_profile
- 测试安装结果
protoc --version
使用Google Protobuf以下步骤参考Google Protobuf的github项目的指南 。第一步:添加maven依赖
com.google.protobuf protobuf-java3.11.0
第二步:编写proto文件Message.proto如何编写.proto文件的相关文档说明 , 可以去官网查看 下面写一个例子 , 请看示范:
syntax = "proto3"; //版本option java_outer_classname = "MessagePojo";//生成的外部类名 , 同时也是文件名message Message {int32 id = 1;//Message类的一个属性 , 属性名称是id , 序号为1string content = 2;//Message类的一个属性 , 属性名称是content , 序号为2}
第三步:使用编译器 , 通过.proto文件生成代码在执行上面的安装步骤后 , 进入到 bin 目录下 , 可以看到一个可执行文件 protoc
cd /usr/local/protobuf/bin/
然后复制前面写好的Message.proto文件到此目录下 , 如图所示:![深入理解Netty编解码、粘包拆包、心跳机制](http://res.youth.cn/img-detail/a44d321b9d7d33d1647b9152a77f3861:492:212.jpg)
输入命令:
protoc --java_out=. Message.proto
然后就可以看到生成的MessagePojo.java文件 。 最后把文件复制到IDEA项目中 。![深入理解Netty编解码、粘包拆包、心跳机制](http://res.youth.cn/img-detail/70527ee7725d40d307b5adc686862ba0:300:113.jpg)
第四步:在发送端添加编码器 , 在接收端添加解码器
客户端添加编码器 , 对消息进行编码 。
【深入理解Netty编解码、粘包拆包、心跳机制】
@Overrideprotected void initChannel(SocketChannel ch) throws Exception { //在发送端添加Protobuf编码器ch.pipeline().addLast(new ProtobufEncoder()); ch.pipeline().addLast(new TcpClientHandler());}
服务端添加解码器 , 对消息进行解码 。@Overrideprotected void initChannel(SocketChannel ch) throws Exception { //添加Protobuf解码器 , 构造器需要指定解码具体的对象实例 ch.pipeline().addLast(new ProtobufDecoder(MessagePojo.Message.getDefaultInstance())); //给pipeline管道设置处理器 ch.pipeline().addLast(new TcpServerHandler());}
第五步:发送消息客户端发送消息 , 代码如下:
@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception { //使用的是构建者模式进行创建对象 MessagePojo.Message message = MessagePojo.Message.newBuilder().setId(1).setContent("一角钱 , 起飞~").build();ctx.writeAndFlush(message);}
服务端接收到数据 , 并且打印:@Overrideprotected void channelRead0(ChannelHandlerContext ctx, MessagePojo.Message messagePojo) throws Exception {System.out.println("id:" + messagePojo.getId());System.out.println("content:" + messagePojo.getContent());}
测试结果正确:![深入理解Netty编解码、粘包拆包、心跳机制](http://res.youth.cn/img-detail/1efa4e8dce88cd55b094e3cb3e875332:415:94.jpg)
分析Protocol的粘包、拆包实际上直接使用Protocol编解码器还是存在粘包问题的 。
证明一下 , 发送端循环一百次发送100条"一角钱 , 起飞"的消息 , 请看发送端代码演示:
@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception { for (int i = 1; i <= 100; i++) {MessagePojo.Message message = MessagePojo.Message.newBuilder().setId(i).setContent(i + "号一角钱 , 起飞~").build();ctx.writeAndFlush(message); }}
这时 , 启动服务端 , 客户端后 , 可能只有打印几条消息或者在控制台看到如下错误:com.google.protobuf.InvalidProtocolBufferException: While parsing a protocol message, the input ended unexpectedly in the middle of a field. This could mean either that the input has been truncated or that an embedded message misreported its own length.
意思是:分析protocol消息时 , 输入意外地在字段中间结束 。 这可能意味着输入被截断 , 或者嵌入的消息误报了自己的长度 。
其实就是粘包问题 , 多条数据合并成一条数据了 , 导致解析出现异常 。
解决Protocol的粘包、拆包问题只需要在发送端加上编码器 ProtobufVarint32LengthFieldPrepender
- 启动|拼多多深入布局母婴产业带 补贴+直播启动“母婴产品溯源”行动
- RFID在冷链物流中的作用-RFID冷链资产管理解决方案
- 《深入理解Java虚拟机》:对象创建、布局和访问全过程
- 都说编程要逻辑好,如何理解这个逻辑
- 关于Netty ByteBuf 的零拷贝
- 成长思维:我大哥对“道法术器”的理解,80%的人不懂
- Linux信号透彻分析理解与各种实例讲解
- 从底层理解this是什么
- 常用的NIO框架-Netty
- 《深入理解Java虚拟机》:锁优化