Netty protobuf使用,自定义Encoder 和DeCoder

Server 监听客户发送的信息,并且打印

Client 发送5s 发送信息。


1.编辑google 的proto文件

Msg.proto

syntax = "proto3";

message Person {  
      
    // ID(必需)  
     int32 id = 1;  
      
    // 姓名(必需)  
     string name = 2;  
      
    // email(可选)  
    string email = 3;  
  
    // 朋友(集合)  
     string friends = 4;  
}  


2.生成java 代码 protoc.exe --java_out=E:\Java Msg.proto


3.编写 client, 

主要结构 业务handler 先底层发送POJO,每割5s 发送一次!

MsgEncoder POJO 转化为   bytebuf


public  class EchoPOJOClient {
    public  void connect() throws InterruptedException, IOException {
        String host="127.0.0.1";
        int port=8081;
        // Configure the client.
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            Bootstrap b = new Bootstrap();
            b.group(workerGroup).channel(NioSocketChannel.class);
            b.handler(new ChannelInitializer<SocketChannel>() {
                public void initChannel(SocketChannel ch) throws Exception {
                    ch.pipeline().addLast(new MsgEncoder());// 用户outbould ,也就是write()     , POJO转化为ByteBuf
                    ch.pipeline().addLast(
                            new EchoClientHander());
                }
            });
            ChannelFuture cf=b.connect(host,port).sync();
            sendTOServer(cf.channel());


            // Wait until the server socket is closed.
        } finally {
            // Shut down all event loops to terminate all threads.
            workerGroup.shutdownGracefully();
        }
    }
    private static final Logger logger = Logger.getLogger(EchoPOJOClient.class.getName());

    public static void main(String str[]) throws InterruptedException, IOException {
        new EchoPOJOClient().connect();
        logger.info("client ........started");
    }

    public void sendTOServer(Channel ch) throws InterruptedException, IOException {

        // Read commands from the stdin.
        System.out.println("Enter text (quit to end)");
        ChannelFuture lastWriteFuture = null;

        // 按照定义的数据结构,创建一个Person  
        Msg.Person.Builder personBuilder = Msg.Person.newBuilder();
        personBuilder.setId(1);
        personBuilder.setName("sdfsdfsf");
        personBuilder.setEmail("xxg@163.com");
        Msg.Person msg = personBuilder.build();

        //5s 发送一次
        for (;;) {
            sleep(5000);//
            ch.writeAndFlush(msg);

        }
    }

    //业务处理handler
    class EchoClientHander extends ChannelInboundHandlerAdapter {
        Logger logger = Logger.getLogger(EchoClientHander.class.getName());
        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            logger.info(msg.toString());
        }

    }
    //   POJO 转化为   bytebuf,  处理用户事件 所以继承ChannelOutboundHandlerAdapter
    class MsgEncoder extends ChannelOutboundHandlerAdapter {


        Logger logger=Logger.getLogger(EchoClientHander.class.getName());

        String hello="hello from client";

        @Override
        public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
            Msg.Person  p=( Msg.Person)msg;

            ByteBuf byteBuf= Unpooled.buffer();
            byteBuf.writeBytes(p.toByteArray());
            byteBuf.writeBytes("\r\n".getBytes()); //加上换行符
            logger.info("MsgEncoder.................");
            ctx.write(byteBuf,promise);// 需要再次写入
        }


        @Override
        public void flush(ChannelHandlerContext ctx) throws Exception {
            super.flush(ctx);
        }
    }



4. Server  

public class EchoPOJOServer {

    public void listen() throws Exception {
        int port=8081;
        // Configure the server. 
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class);
            b.handler(new LoggingHandler(LogLevel.DEBUG));

            b.childHandler(new ChannelInitializer<SocketChannel>() {
                public void initChannel(SocketChannel ch) throws Exception {
                    ch.pipeline().addLast(new LineBasedFrameDecoder(1024));// 根据 分隔符(换行符)分割,分割后还是一个 ByteBuf
                    ch.pipeline().addLast(new MsgDecoder());//  客户需要发送信息, ByteBuf 转化为 POJO
                    ch.pipeline().addLast(
                            new EchoServerHandler()); // 业务处理类
                }
            });
            ChannelFuture cf=b.bind(port).sync();
            cf.channel().closeFuture().sync();
            // Wait until the server socket is closed.
        } finally {
            // Shut down all event loops to terminate all threads. 
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
    private static final Logger logger = Logger.getLogger(EchoPOJOServer.class.getName());

    public static void main(String str[]) throws Exception {
        new EchoPOJOServer().listen();
        logger.info("server ........started");
    }
      //业务处理handler
     class EchoServerHandler extends ChannelInboundHandlerAdapter {
        private  final Logger logger = Logger.getLogger(EchoServerHandler.class.getName());
        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            logger.info("server read......"+msg.toString());
        }
        @Override
        public void channelInactive(ChannelHandlerContext ctx) throws Exception {
            logger.info("chanle is closed ");
        }
    }
    //  bytebuf  转化为  POJO ,  处理io 事件,继承ChannelInboundHandlerAdapter
    class MsgDecoder extends ChannelInboundHandlerAdapter {
        Logger logger=Logger.getLogger(MsgDecoder.class.getName());
        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            ByteBuf  bytebuf= (ByteBuf) msg;
            // bytebuf.array();// 报错 java.lang.UnsupportedOperationException: direct buffer  还没有分析到位
            byte [] b=new byte[bytebuf.readableBytes()];
            bytebuf.readBytes(b);
            Msg.Person xxg2 = Msg.Person.parseFrom(b);
            logger.info("MsgDecoder................."+xxg2.toString());
            ctx.fireChannelRead(xxg2);
        }


    }





发布了4 篇原创文章 · 获赞 0 · 访问量 6517
展开阅读全文

protobuf跨语言传输出错

09-29

我是用python作服务器,发送数据到Android客户端。用的是同一个.proto文件分别用--python跟--java指令生成协议,分别添加到python跟Android。 但是Android端一直解析错误,错误提示如下: Caused by: com.google.protobuf.InvalidProtocolBufferException: Protocol message contained an invalid tag (zero). google了半天没找到正确的解决方法,请大神帮忙看看。以下是代码: python代码: entity = SubscribeRespProto_pb2.SubscribeRespProto() entity.subReqID = 1 entity.userName = "H2901" entity.productName = "qao" entity.address = "guangzhou" content = entity.SerializeToString() print(str(entity)) proto.transport.write(content) Android端用的是Netty4.1.5,关键代码如下: Bootstrap bootstrap = new Bootstrap(); bootstrap.group(eventLoopGroup) .channel(NioSocketChannel.class) .option(ChannelOption.SO_KEEPALIVE, true) .handler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel socketChannel) throws Exception { socketChannel.pipeline().addLast(new ProtobufVarint32FrameDecoder()) .addLast(new ProtobufDecoder(SubscribeReqProto.SubscribeReq.getDefaultInstance())) .addLast(new ProtobufVarint32LengthFieldPrepender()) .addLast(new ProtobufEncoder()) .addLast(new SubReqClientHandler()); } }); channelFuture = bootstrap.connect(Constants.IP, Constants.PORT).sync(); .proto文件如下: message SubscribeRespProto{ required int32 subReqID = 1; required string userName = 2; required string productName = 3; required string address = 4; } 问答

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览