ネッティー学習と統合--NettyいるProtobuf(B)
このプログラムは、2つの明らかな問題があり、結合が強すぎて、ユニバーサルデコーダが存在しない、欠陥があるが、どのようにそれを解決するために?
例えば:コードを使用することができない前に、内部タイプPERSON2と相まって。
質問1:クライアントとサーバーは、それぞれのデコーダチップを行くここに書くことはできません
質問2:ジェネリック内部クライアントとサーバー側のハンドラが、また、書き込みダイが行くことができません
スタックオーバーフローは、この問題を解決するために、検索エンジンを十分に活用します
上記の検索結果のスタックオーバーフロー
https://stackoverflow.com/questions/38363160/netty-protobuf-websocket-how-to-convert-binarywebsocketframe-to-protobuf-type
ネッティーいるProtobufデコーダを統合する方法を、開口部:グーグルいくつかの記事前に見
https://www.cnblogs.com/Binhua-Liu/p/5577622.htmlを
非常に詳細な、2つの方法を提供しています
方法1:カスタムプロトコルを持って、公式サイトに基づくネッティーカスタムプロトコル提供
方法2:メッセージを定義することによって、問題を解決する方法を
次のように二つの方法を詳述
外層中1.メッセージを定義します。
あなたが渡したいというタイプを決定するためにどのような列挙2
構文= 「proto2 」。 パッケージcom.dawa.protobuf。 optimize_forオプション = SPEED; option java_package ="com.dawa.netty.sixthexample"; option java_outer_classname = "MyDataInfo"; message MyMessage{ enum DataType{ PersonType = 1; DogType = 2; CatType =3; } required DataType data_type = 1; oneof dataBody{ Person person =2; Dog dog = 3; Cat cat = 4; } } message Person{ optional string name = 1; optional int32 age = 2; optional string address = 3; } message Dog{ optional string name = 1; optional int32 age = 2; } message Cat{ optional string name = 1; optional string city = 2; }
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 { } }
先启动服务器端,再启动客户端,成功获取到客户端发送的消息到服务器端,效果图如下
点了好多下才随机出来的大娃,哈哈