黑马程序员技术交流社区

标题: 【成都校区*使用Google ProtoBuff完成RPC服务的通信】 [打印本页]

作者: 小蜀哥哥    时间: 2019-6-13 19:14
标题: 【成都校区*使用Google ProtoBuff完成RPC服务的通信】
本帖最后由 小蜀哥哥 于 2019-6-13 19:14 编辑

需求:
    使用netty完成一个RPC服务器的编写和调用,在通信的过程中使用protobuff来传递数据
前提:
    protobuff官网:https://developers.google.com/protocol-buffers/ (需要翻墙)
困惑:
    RPC和RMI的区别?
        原理都是类似的,只是RMI是使用Java编写的不能跨语言,RPC是支持跨语言的
    RPC和webservice的区别
        webservice 使用http协议进行通信,RPC使用socket进行通信,socket效率更高
        webservice使用xml进行数据通信,xml最臭名昭著的就是比较占空间,而且遍历和查找很不方法,rpc使用体积更小,速度更快,解析更强的框架进行数据传递(数据的压缩比决定了数据的大小),日入使用Google protobuff 、grpc、apache thrift等。
protobuf 的学习过程
    1. 首先找到官网学习一下什么是protobuf

   2. 下载protobuf的编译器(https://github.com/google/protobuf)

  3. 配置protobuff编译器的环境变量

  4. 阅读protobuff的文档(https://developers.google.com/protocol-buffers/docs/javatutorial)

       编写protobuff程序主要有散步

   5. protobuff解决的问题

netty集成protobufff完成RPC的方法调用

实现步骤:

1. 进入protobuff需要jar包

2. 编写protobuff的.proto文件(该文件我们也成为idl(interface description language)文件)

[Java] 纯文本查看 复制代码
syntax = "proto2";
package com.baidu.netty.proto;
option java_package = "com.baidu.netty.sixExample";
option java_outer_classname = "TeacherData";
option optimize_for=SPEED;

message Teacher
{
    required int32 id = 1;
    optional string name = 2;

    enum GenderType
    {
        MALE = 0;
        FEMALE = 1;
    }
    message Student
    {
        required int32 id = 1;
        optional string name = 2;
        optional string email = 3;
        optional GenderType gender = 4 [default = MALE];
    }
}

3. 使用protobuff的编译器生产代码(几乎所有的RPC框架都有代码生成框架)

    protoc --java_out=代码存放的目录  .proto文件存放的位置

4. 简单测试生成的类是否能够使用

[AppleScript] 纯文本查看 复制代码
package com.baidu.netty.sixExample;

public class TestTearcher {
    public static void main(String[] args) throws Exception{
        TeacherData.Teacher teacher = TeacherData.Teacher.newBuilder().setId(1).setName("老徐").build();
        System.out.println(teacher.getName());
        //对象的序列号
        byte[] temp = teacher.toByteArray();
        //对象的反序列号
        TeacherData.Teacher teacher1 = TeacherData.Teacher.parseFrom(temp);
        System.out.println(teacher1.getName());

    }
}

5. 编写netty的服务器端启动程序

[AppleScript] 纯文本查看 复制代码
package com.baidu.netty.sixExample;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;

public class MyServer {
    public static void main(String[] args) throws Exception{
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(bossGroup,workerGroup).channel(NioServerSocketChannel.class).childHandler(new MyServerInitializer());
            ChannelFuture future = bootstrap.bind(8899).sync();
            future.channel().closeFuture().sync();
        }finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}

6. 编写服务器端初始化类

[AppleScript] 纯文本查看 复制代码
package com.baidu.netty.sixExample;

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;

public class MyServerInitializer extends ChannelInitializer<SocketChannel> {
    @Override
    protected void initChannel(SocketChannel ch) throws Exception {
        ChannelPipeline pipeline = ch.pipeline();
        pipeline.addLast(new ProtobufVarint32FrameDecoder());
        pipeline.addLast(new ProtobufDecoder(TeacherData.Teacher.getDefaultInstance()));
        pipeline.addLast(new ProtobufVarint32LengthFieldPrepender());
        pipeline.addLast(new ProtobufEncoder());
        pipeline.addLast(new MyServerHandler());
    }
}

7. 编写服务器端处理类

[AppleScript] 纯文本查看 复制代码
package com.baidu.netty.sixExample;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;

public class MyServerHandler extends SimpleChannelInboundHandler<TeacherData.Teacher> {
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, TeacherData.Teacher msg) throws Exception {
        System.out.println(msg.getName());
        System.out.println(msg.getId());
    }
}

8. 编写客户端启动类

[AppleScript] 纯文本查看 复制代码
package com.baidu.netty.sixExample;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;

public class MyClient {
    public static void main(String[] args) throws Exception{
        EventLoopGroup client = new NioEventLoopGroup();
        try {
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(client).channel(NioSocketChannel.class).handler(new MyClientInitializer());
            ChannelFuture future = bootstrap.connect("localhost",8899).sync();
            Channel channel = future.channel();
            TeacherData.Teacher teacher = TeacherData.Teacher.newBuilder().setName("老徐").setId(1).build();
            channel.writeAndFlush(teacher);
            channel.closeFuture().sync();
        }finally {
            client.shutdownGracefully();
        }
    }
}

9. 编写客户端初始化类

[AppleScript] 纯文本查看 复制代码
package com.baidu.netty.sixExample;

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;

public class MyClientInitializer extends ChannelInitializer<SocketChannel> {
    @Override
    protected void initChannel(SocketChannel ch) throws Exception {
        ChannelPipeline pipeline = ch.pipeline();
        pipeline.addLast(new ProtobufVarint32FrameDecoder());
        pipeline.addLast(new ProtobufDecoder(TeacherData.Teacher.getDefaultInstance()));
        pipeline.addLast(new ProtobufVarint32LengthFieldPrepender());
        pipeline.addLast(new ProtobufEncoder());
    }
}

10. 测试客户端向服务器端发送对象







欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2