Netty学习——Netty和Protobuf的整合(二)


这程序是有瑕疵的,解码器那里不通用,耦合性太强,有两个很明显的问题,但是要怎么解决呢?
如:再加一个内部类型 Person2,之前的代码就不能用了。

问题1:客户端和服务器端 分别 这里解码器都不能写死吧

问题2:客户端和服务器端Handler里面的泛型,也都不能写死吧

Stack Overflow , 善用搜索引擎解决此问题

在Stack Overflow上面搜的结果
https://stackoverflow.com/questions/38363160/netty-protobuf-websocket-how-to-convert-binarywebsocketframe-to-protobuf-type
Google:netty如何集成Protobuf的解码器,点开了前几篇帖子看了看
https://www.cnblogs.com/Binhua-Liu/p/5577622.html
里面提供了两种解决方案,挺详细的

方法一:自定义协议,官网提供的有基于Netty的自定义协议的方法
方法二: 通过消息的定义方式去解决问题

方法二详解如下:
1.在外层,就定义一个消息。
2.通过枚举,来决定你要传递的类型是什么

syntax ="proto2";

package com.dawa.protobuf;

option optimize_for = SPEED;
option java_package ="com.dawa.netty.sixthexample";
option java_outer_classname = "MyDataInfo"; message MyMessage{
enum DataType{
PersonType = ;
DogType = ;
CatType =;
} required DataType data_type = ; oneof dataBody{
Person person =;
Dog dog = ;
Cat cat = ;
}
} message Person{
optional string name = ;
optional int32 age = ;
optional string address = ;
} message Dog{
optional string name = ;
optional int32 age = ;
} message Cat{
optional string name = ;
optional string city = ;
}

oneof 关键词
1.共享内存
2.只存在一个

使用protoc 重新生成一下proto文件

然后修改 客户端和服务端的初始化器的类,从以前单一的指定修改成 枚举类型的指定

修改之后的服务器端  Handler和Initializer代码

package com.dawa.netty.sixthexample;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler; /**
* @Title: TestServerHandler
* @Author: 大娃
* @Date: 2019/12/3 10:09
* @Description: handler本身是个泛型,这里的泛型就是取 要处理的类型
*/
public class TestServerHandler extends SimpleChannelInboundHandler<MyDataInfo.MyMessage> { @Override
protected void channelRead0(ChannelHandlerContext ctx, MyDataInfo.MyMessage msg) throws Exception {
MyDataInfo.MyMessage.DataType dataType = msg.getDataType();
if (dataType == MyDataInfo.MyMessage.DataType.PersonType) {
MyDataInfo.Person person = msg.getPerson();
System.out.println(person.getName());
System.out.println(person.getAge());
System.out.println(person.getAddress());
} else if (dataType == MyDataInfo.MyMessage.DataType.DogType) {
MyDataInfo.Dog dog = msg.getDog();
System.out.println(dog.getAge());
System.out.println(dog.getName());
} else {
MyDataInfo.Cat cat = msg.getCat();
System.out.println(cat.getName());
System.out.println(cat.getCity());
}
}
}
package com.dawa.netty.sixthexample;

import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
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; /**
* @Title: TestServerInitializer
* @Author: 大娃
* @Date: 2019/12/3 10:05
* @Description:
*/
public class TestServerInitializer extends ChannelInitializer<SocketChannel> { @Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
//这里和之前的不一样了,但也就是处理器的不一样
//编解码处理器,protobuf提供的专门的编解码器.4个处理器
pipeline.addLast(new ProtobufVarint32FrameDecoder());
//Decoder是重点,解码器,将字节码转换成想要的数据类型
//参数 messageLite,外层的要转换的类的实例
pipeline.addLast(new ProtobufDecoder(MyDataInfo.MyMessage.getDefaultInstance()));
pipeline.addLast(new ProtobufVarint32LengthFieldPrepender());
pipeline.addLast(new ProtobufEncoder());
pipeline.addLast(new TestServerHandler());
}
}

修改之后的客户端  Handler和Initializer的代码

package com.dawa.netty.sixthexample;

import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
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; /**
* @Title: TestClientInitializer
* @Author: 大娃
* @Date: 2019/12/3 10:43
* @Description:
*/
public class TestClientInitializer extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
//这里和之前的不一样了,但也就是处理器的不一样
//编解码处理器,protobuf提供的专门的编解码器.4个处理器
pipeline.addLast(new ProtobufVarint32FrameDecoder());
//Decoder是重点,解码器,将字节码转换成想要的数据类型
//参数 messageLite,外层的要转换的类的实例
pipeline.addLast(new ProtobufDecoder(MyDataInfo.MyMessage.getDefaultInstance()));
pipeline.addLast(new ProtobufVarint32LengthFieldPrepender());
pipeline.addLast(new ProtobufEncoder());
//自己的处理器
pipeline.addLast(new TestClientHandler());
}
}
package com.dawa.netty.sixthexample;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler; import java.util.Random; /**
* @Title: TestClientHandler
* @Author: 大娃
* @Date: 2019/12/3 10:44
* @Description:
*/
public class TestClientHandler extends SimpleChannelInboundHandler<MyDataInfo.MyMessage> { @Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
//处于活动状态
int randomInt = new Random().nextInt(3);
MyDataInfo.MyMessage myMessage = null; if (0 == randomInt) {
myMessage = MyDataInfo.MyMessage.newBuilder().
setDataType(MyDataInfo.MyMessage.DataType.PersonType).
setPerson(MyDataInfo.Person.newBuilder().
setName("大娃").
setAge(22).
setAddress("北京").build()).
build();
} else if (1 == randomInt) {
myMessage = MyDataInfo.MyMessage.newBuilder().
setDataType(MyDataInfo.MyMessage.DataType.DogType).
setDog(MyDataInfo.Dog.newBuilder().
setName("一只狗").
setAge(2).build()).
build();
} else {
myMessage = MyDataInfo.MyMessage.newBuilder().
setDataType(MyDataInfo.MyMessage.DataType.CatType).
setCat(MyDataInfo.Cat.newBuilder().
setName("一只猫").setCity("上海").build()).
build();
}
ctx.channel().writeAndFlush(myMessage);
} @Override
protected void channelRead0(ChannelHandlerContext ctx, MyDataInfo.MyMessage msg) throws Exception { }
}

先启动服务器端,再启动客户端,成功获取到客户端发送的消息到服务器端,效果图如下

点了好多下才随机出来的大娃,哈哈

Netty学习——Netty和Protobuf的整合(二)的更多相关文章

  1. Netty学习——Netty和Protobuf的整合(一)

    Netty学习——Netty和Protobuf的整合 Protobuf作为序列化的工具,将序列化后的数据,通过Netty来进行在网络上的传输 1.将proto文件里的java包的位置修改一下,然后再执 ...

  2. netty学习--netty源码中的部分util方法

    io.netty.buffer.AbstractByteBuf#calculateNewCapacity  申请内存空间 private int calculateNewCapacity(int mi ...

  3. Netty学习篇③--整合springboot

    经过前面的netty学习,大概了解了netty各个组件的概念和作用,开始自己瞎鼓捣netty和我们常用的项目的整合(很简单的整合) 项目准备 工具:IDEA2017 jar包导入:maven 项目框架 ...

  4. Netty 学习(二):服务端与客户端通信

    Netty 学习(二):服务端与客户端通信 作者: Grey 原文地址: 博客园:Netty 学习(二):服务端与客户端通信 CSDN:Netty 学习(二):服务端与客户端通信 说明 Netty 中 ...

  5. Netty学习笔记(二) 实现服务端和客户端

    在Netty学习笔记(一) 实现DISCARD服务中,我们使用Netty和Python实现了简单的丢弃DISCARD服务,这篇,我们使用Netty实现服务端和客户端交互的需求. 前置工作 开发环境 J ...

  6. Netty学习(二)使用及执行流程

    Netty简单使用 1.本文先介绍一下 server 的 demo 2.(重点是这个)根据代码跟踪一下 Netty 的一些执行流程 和 事件传递的 pipeline. 首先到官网看一下Netty Se ...

  7. Netty学习二:Java IO与序列化

    1 Java IO 1.1 Java IO 1.1.1 IO IO,即输入(Input)输出(Output)的简写,是描述计算机软硬件对二进制数据的传输.读写等操作的统称. 按照软硬件可分为: 磁盘I ...

  8. MINA、Netty、Twisted一起学(十二):HTTPS

    由于HTTPS协议是由HTTP协议加上SSL/TLS协议组合而成,在阅读本文前可以先阅读一下HTTP服务器和SSL/TLS两篇博文,本文中的代码也是由这两篇博文中的代码组合而成. HTTPS介绍 上一 ...

  9. Netty学习第一节Netty的总体概况

    一.Netty简介 什么是Netty? 1.高性能事件驱动,异步非阻塞的IO加载开源框架. 它是由JBoss提供,用于建立TCP等底层链接.基于Netty可以建立高性能的HTTP服务器,快速开发高性能 ...

随机推荐

  1. 【模板】prufer序列

    如何构造一个prufer序列? 我们给一棵无根树的节点编上号,每次找到一个编号最小的度为1节点,删除它,并输出与它连接的点的编号,直到只剩下两个节点. 这样,我们就构造出来了一个prufer序列. 通 ...

  2. [考试反思]1011csp-s模拟测试68:守恒

    在RP守恒定律的持续作用下, 不出所料,这场稍炸 还有10分钟就是下一场了,但愿继续守恒? 改题太慢了,连写博的时间都没有了 然而最后还是在吃饭前彻彻底底改出来了 的确是个菜鸡 所以今天的题解只能先咕 ...

  3. [考试反思]0921csp-s模拟测试49:困顿

    太弱.还是太弱. 拉不开分差,离第一机房分数线估计还是300多分. 但是,还是要骂:XX出题人. 部分分非常少且没有意义,T1基本只有0/纯暴力20/100三个档, T2正解是n2但是n3一分不给,还 ...

  4. Android 开源库 GitHub 托管

    本文微信公众号「AndroidTraveler」首发. 背景 之前给大家写过一篇文章 Android 上传开源项目到 jcenter 实战踩坑之路,分享了上传开源项目到 jcenter 上面的一些踩坑 ...

  5. 通俗易懂了解React生命周期

    1.前言 学习React时,学习组件的生命周期是非常重要的,了解了组件的"从无到有再到无"所经历的各个状态,对日后写高性能的组件会有很大的帮助. 2.生命周期图 React的生命周 ...

  6. day1 晚上 P4145 上帝造题的七分钟2 / 花神游历各国 线段树

    #include<iostream> #include<cstdio> #include<cmath> using namespace std; ; struct ...

  7. Android 开发中是否应该使用枚举?

    本文由咕咚发布在个人博客,转载请注明出处. 本文永久地址:https://gudong.name/2019/11/04/use-enum-or-not.html 在 Android 官方文档推出性能优 ...

  8. 大数据之路day02_1--运算符

    运算符这一节主要是介绍算数运算符.赋值运算符.比较运算符.逻辑运算符.三元运算符.接下来一一介绍. 1.算数运算符 ++ 和 -- 的用法 例如:a++ 和 ++a的区别 %的应用场景(取模其实就是取 ...

  9. 关于css中的字体样式

    1.决定字体的属性 color:字体颜色  属性值:单词,十六进制表示,rgb 2.字体大小 font-size:12px:属性值是整数字,不要带小数,单位是px叫做像素单位:凡是由像素拼成的图片我们 ...

  10. ASP.NET Core 3 使用原生 依赖注入 集成 AspectCore ,实现 AOP 功能

    在NETCORE中可以使用AOP的方式有很多很多,包括国内优秀的开源框架asp.netcore同样可以实现AOP编程模式.   IOC方面,个人喜欢net core 3自带的DI,因为他注册服务简洁优 ...