netty粘包(十)ProtobufDecoder & ProtobufEncoder
syntax = "proto2";
package myproto;
option java_package = "com.jds.test.proto";
option java_outer_classname = "MyBaseProto";
enum Type {
ONE = 1;
TWO = 2;
THREE = 3;
}
message Body {
repeated string l = 1; // repeated 列表
map<string, string> m = 2; //
optional Type type = 3;
}
message BaseProto {
required int32 code = 1;// 默认值,表示成员只有0个或者1个
required string msg = 2;//
optional Body result = 3;
}
msg.proto
protoc-3.6.1-osx-x86_64/bin/protoc --proto_path ./ --java_out ./ msg.proto
class ClientHandler4 extends SimpleChannelInboundHandler<MyBaseProto.BaseProto> {
//接受服务端发来的消息
@Override
protected void channelRead0(ChannelHandlerContext ctx, MyBaseProto.BaseProto msg) throws Exception {
System.out.println("server response : "+msg.toString());
}
//与服务器建立连接
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
//给服务器发消息
//发送5次消息
for (int i = 0; i < 5; i++) {
MyBaseProto.BaseProto.Builder builder = MyBaseProto.BaseProto.newBuilder();
builder.setCode(i);
builder.setMsg("msg" + i);
MyBaseProto.Body.Builder body = MyBaseProto.Body.newBuilder();
body.addL(String.valueOf(i * 10));
body.addL(String.valueOf(i * i));
MyBaseProto.Type type = MyBaseProto.Type.ONE;
body.setType(type);
builder.setResult(body);
ctx.channel().writeAndFlush(builder.build());
}
}
class ServerHandler4 extends SimpleChannelInboundHandler<MyBaseProto.BaseProto> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, MyBaseProto.BaseProto msg) throws Exception {
System.out.println("RESPONSE--------"+msg.toString());
MyBaseProto.BaseProto.Builder builder = MyBaseProto.BaseProto.newBuilder(msg);
builder.setCode(msg.getCode() + 100);
ctx.writeAndFlush(builder.build()).
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
//获取管道
ChannelPipeline pipeline = socketChannel.pipeline();
pipeline.addLast(new LengthFieldBasedFrameDecoder(10000, 0, 4, 0, 4));
pipeline.addLast(new ProtobufDecoder(MyBaseProto.BaseProto.getDefaultInstance()));
pipeline.addLast(new LengthFieldPrepender(4));
pipeline.addLast(new ProtobufEncoder());
//处理类
pipeline.addLast(new ClientHandler4());
}
});
bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
//获取管道
ChannelPipeline pipeline = socketChannel.pipeline();
pipeline.addLast(new LengthFieldBasedFrameDecoder(10000, 0, 4, 0, 4));
pipeline.addLast(new ProtobufDecoder(MyBaseProto.BaseProto.getDefaultInstance()));
pipeline.addLast(new LengthFieldPrepender(4));
pipeline.addLast(new ProtobufEncoder());
//处理类
pipeline.addLast(new ServerHandler4());
}
});
+ <dependency> + <groupId>com.google.protobuf</groupId> + <artifactId>protobuf-java</artifactId> + <version>3.6.1</version> + </dependency>
服务端输出:
fanxindeMacBook-Air:action sunyuming$ java -jar target/netty-in-action-0.1-SNAPSHOT-jar-with-dependencies.jar
server start ......
channelActive
RESPONSE--------code: 0
msg: "msg0"
result {
l: "0"
l: "0"
type: ONE
}
RESPONSE--------code: 1
msg: "msg1"
result {
l: "10"
l: "1"
type: ONE
}
RESPONSE--------code: 2
msg: "msg2"
result {
l: "20"
l: "4"
type: ONE
}
RESPONSE--------code: 3
msg: "msg3"
result {
l: "30"
l: "9"
type: ONE
}
RESPONSE--------code: 4
msg: "msg4"
result {
l: "40"
l: "16"
type: ONE
}
客户端输出:
server response : code: 100
msg: "msg0"
result {
l: "0"
l: "0"
type: ONE
}
server response : code: 101
msg: "msg1"
result {
l: "10"
l: "1"
type: ONE
}
server response : code: 102
msg: "msg2"
result {
l: "20"
l: "4"
type: ONE
}
server response : code: 103
msg: "msg3"
result {
l: "30"
l: "9"
type: ONE
}
server response : code: 104
msg: "msg4"
result {
l: "40"
l: "16"
type: ONE
}
笔记:
1 protobuf编译器与maven应一致,本例为3.6.1
2 proto2不支持map,但可以运行;proto3不需要optional和required,否则会报错 ;本例为proto2
3 一如既往,netty 4.0.17.Final
浙公网安备 33010602011771号