需求:
使用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 teacher 1 = TeacherData.Teacher.parseFrom ( temp ) ;
System.out.println ( teacher 1. 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.ProtobufVarint 32 FrameDecoder;
import io.netty.handler.codec.protobuf.ProtobufVarint 32 LengthFieldPrepender;
public class MyServerInitializer extends ChannelInitializer < SocketChannel > {
@Override
protected void initChannel ( SocketChannel ch ) throws Exception {
ChannelPipeline pipeline = ch.pipeline ( ) ;
pipeline.addLast ( new ProtobufVarint 32 FrameDecoder ( ) ) ;
pipeline.addLast ( new ProtobufDecoder ( TeacherData.Teacher.getDefaultInstance ( ) ) ) ;
pipeline.addLast ( new ProtobufVarint 32 LengthFieldPrepender ( ) ) ;
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 channelRead 0 ( 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.ProtobufVarint 32 FrameDecoder;
import io.netty.handler.codec.protobuf.ProtobufVarint 32 LengthFieldPrepender;
public class MyClientInitializer extends ChannelInitializer < SocketChannel > {
@Override
protected void initChannel ( SocketChannel ch ) throws Exception {
ChannelPipeline pipeline = ch.pipeline ( ) ;
pipeline.addLast ( new ProtobufVarint 32 FrameDecoder ( ) ) ;
pipeline.addLast ( new ProtobufDecoder ( TeacherData.Teacher.getDefaultInstance ( ) ) ) ;
pipeline.addLast ( new ProtobufVarint 32 LengthFieldPrepender ( ) ) ;
pipeline.addLast ( new ProtobufEncoder ( ) ) ;
}
} < / font > < / font > < / font >
|
10. 测试客户端向服务器端发送对象