需求:
使用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)文件)
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
<font style="color:rgb(77, 77, 77)"><font face="""><font style="font-size:16px">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]; }}</font></font></font> |
3. 使用protobuff的编译器生产代码(几乎所有的RPC框架都有代码生成框架)
protoc --java_out=代码存放的目录 .proto文件存放的位置
4. 简单测试生成的类是否能够使用
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
<font style="color:rgb(77, 77, 77)"><font face="""><font style="font-size:16px">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()); }}</font></font></font> |
5. 编写netty的服务器端启动程序
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
<font style="color:rgb(77, 77, 77)"><font face="""><font style="font-size:16px">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(); } }}</font></font></font> |
6. 编写服务器端初始化类
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
|
<font style="color:rgb(77, 77, 77)"><font face="""><font style="font-size:16px">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()); }}</font></font></font> |
7. 编写服务器端处理类
|
01
02
03
04
05
06
07
08
09
10
11
12
|
<font style="color:rgb(77, 77, 77)"><font face="""><font style="font-size:16px">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()); }}</font></font></font> |
8. 编写客户端启动类
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
<font style="color:rgb(77, 77, 77)"><font face="""><font style="font-size:16px">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(); } }}</font></font></font> |
9. 编写客户端初始化类
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
|
<font style="color:rgb(77, 77, 77)"><font face="""><font style="font-size:16px">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()); }}</font></font></font> |
10. 测试客户端向服务器端发送对象