1 ProtoBuf实战:需求
编程程序,使用ProtoBuf完成如下功能
1、客户端发送一个Student POJO对象到服务器(通过ProtoBuf编码)
2、服务端能接收Student POJO对象,并显示信息(通过ProtoBuf解码)
1.1 编写Student.proto文件
首先在pom.xml中导入protobuf坐标。
<dependency><groupId>com.google.protobuf</groupId><artifactId>protobuf-java</artifactId><version>3.6.1</version> </dependency>
编写Student.proto文件
syntax = "proto3";//版本 option java_outer_classname = "StudentPOJO";//生成的外部类名,同时也是文件名 message Student { //会在 StudentPOJO 外部类生成一个内部类 Student, 他是真正发送的POJO对象int32 id = 1; // Student 类中有 一个属性 名字为 id 类型为int32(protobuf类型) 1表示属性序号,不是值string name = 2; }
自行下载 protoc-3.6.1-win32.zip,解压。把Student.proto文件放入\protoc-3.6.1-win32\bin目录下,执行如下命令:
protoc.exe --java_out=. Student.proto
生成StudentPOJO.java文件。代码如下:
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: Student.protopublic final class StudentPOJO {private StudentPOJO() {}public static void registerAllExtensions(com.google.protobuf.ExtensionRegistryLite registry) {}public static void registerAllExtensions(com.google.protobuf.ExtensionRegistry registry) {registerAllExtensions((com.google.protobuf.ExtensionRegistryLite) registry);}public interface StudentOrBuilder extends// @@protoc_insertion_point(interface_extends:Student)com.google.protobuf.MessageOrBuilder {/*** <pre>* Student 类中有 一个属性 名字为 id 类型为int32(protobuf类型) 1表示属性序号,不是值* </pre>** <code>int32 id = 1;</code>*/int getId();/*** <code>string name = 2;</code>*/java.lang.String getName();/*** <code>string name = 2;</code>*/com.google.protobuf.ByteStringgetNameBytes();}/*** <pre>*会在 StudentPOJO 外部类生成一个内部类 Student, 他是真正发送的POJO对象* </pre>** Protobuf type {@code Student}*/public static final class Student extendscom.google.protobuf.GeneratedMessageV3 implements// @@protoc_insertion_point(message_implements:Student)StudentOrBuilder {private static final long serialVersionUID = 0L;// Use Student.newBuilder() to construct.private Student(com.google.protobuf.GeneratedMessageV3.Builder<?> builder) {super(builder);}private Student() {id_ = 0;name_ = "";}@java.lang.Overridepublic final com.google.protobuf.UnknownFieldSetgetUnknownFields() {return this.unknownFields;}private Student(com.google.protobuf.CodedInputStream input,com.google.protobuf.ExtensionRegistryLite extensionRegistry)throws com.google.protobuf.InvalidProtocolBufferException {this();if (extensionRegistry == null) {throw new java.lang.NullPointerException();}int mutable_bitField0_ = 0;com.google.protobuf.UnknownFieldSet.Builder unknownFields =com.google.protobuf.UnknownFieldSet.newBuilder();try {boolean done = false;while (!done) {int tag = input.readTag();switch (tag) {case 0:done = true;break;case 8: {id_ = input.readInt32();break;}case 18: {java.lang.String s = input.readStringRequireUtf8();name_ = s;break;}default: {if (!parseUnknownFieldProto3(input, unknownFields, extensionRegistry, tag)) {done = true;}break;}}}} catch (com.google.protobuf.InvalidProtocolBufferException e) {throw e.setUnfinishedMessage(this);} catch (java.io.IOException e) {throw new com.google.protobuf.InvalidProtocolBufferException(e).setUnfinishedMessage(this);} finally {this.unknownFields = unknownFields.build();makeExtensionsImmutable();}}public static final com.google.protobuf.Descriptors.DescriptorgetDescriptor() {return StudentPOJO.internal_static_Student_descriptor;}@java.lang.Overrideprotected com.google.protobuf.GeneratedMessageV3.FieldAccessorTableinternalGetFieldAccessorTable() {return StudentPOJO.internal_static_Student_fieldAccessorTable.ensureFieldAccessorsInitialized(StudentPOJO.Student.class, StudentPOJO.Student.Builder.class);}public static final int ID_FIELD_NUMBER = 1;private int id_;/*** <pre>* Student 类中有 一个属性 名字为 id 类型为int32(protobuf类型) 1表示属性序号,不是值* </pre>** <code>int32 id = 1;</code>*/public int getId() {return id_;}public static final int NAME_FIELD_NUMBER = 2;private volatile java.lang.Object name_;/*** <code>string name = 2;</code>*/public java.lang.String getName() {java.lang.Object ref = name_;if (ref instanceof java.lang.String) {return (java.lang.String) ref;} else {com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref;java.lang.String s = bs.toStringUtf8();name_ = s;return s;}}/*** <code>string name = 2;</code>*/public com.google.protobuf.ByteStringgetNameBytes() {java.lang.Object ref = name_;if (ref instanceof java.lang.String) {com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8((java.lang.String) ref);name_ = b;return b;} else {return (com.google.protobuf.ByteString) ref;}}private byte memoizedIsInitialized = -1;@java.lang.Overridepublic final boolean isInitialized() {byte isInitialized = memoizedIsInitialized;if (isInitialized == 1) return true;if (isInitialized == 0) return false;memoizedIsInitialized = 1;return true;}@java.lang.Overridepublic void writeTo(com.google.protobuf.CodedOutputStream output)throws java.io.IOException {if (id_ != 0) {output.writeInt32(1, id_);}if (!getNameBytes().isEmpty()) {com.google.protobuf.GeneratedMessageV3.writeString(output, 2, name_);}unknownFields.writeTo(output);}@java.lang.Overridepublic int getSerializedSize() {int size = memoizedSize;if (size != -1) return size;size = 0;if (id_ != 0) {size += com.google.protobuf.CodedOutputStream.computeInt32Size(1, id_);}if (!getNameBytes().isEmpty()) {size += com.google.protobuf.GeneratedMessageV3.computeStringSize(2, name_);}size += unknownFields.getSerializedSize();memoizedSize = size;return size;}@java.lang.Overridepublic boolean equals(final java.lang.Object obj) {if (obj == this) {return true;}if (!(obj instanceof StudentPOJO.Student)) {return super.equals(obj);}StudentPOJO.Student other = (StudentPOJO.Student) obj;boolean result = true;result = result && (getId()== other.getId());result = result && getName().equals(other.getName());result = result && unknownFields.equals(other.unknownFields);return result;}@java.lang.Overridepublic int hashCode() {if (memoizedHashCode != 0) {return memoizedHashCode;}int hash = 41;hash = (19 * hash) + getDescriptor().hashCode();hash = (37 * hash) + ID_FIELD_NUMBER;hash = (53 * hash) + getId();hash = (37 * hash) + NAME_FIELD_NUMBER;hash = (53 * hash) + getName().hashCode();hash = (29 * hash) + unknownFields.hashCode();memoizedHashCode = hash;return hash;}public static StudentPOJO.Student parseFrom(java.nio.ByteBuffer data)throws com.google.protobuf.InvalidProtocolBufferException {return PARSER.parseFrom(data);}public static StudentPOJO.Student parseFrom(java.nio.ByteBuffer data,com.google.protobuf.ExtensionRegistryLite extensionRegistry)throws com.google.protobuf.InvalidProtocolBufferException {return PARSER.parseFrom(data, extensionRegistry);}public static StudentPOJO.Student parseFrom(com.google.protobuf.ByteString data)throws com.google.protobuf.InvalidProtocolBufferException {return PARSER.parseFrom(data);}public static StudentPOJO.Student parseFrom(com.google.protobuf.ByteString data,com.google.protobuf.ExtensionRegistryLite extensionRegistry)throws com.google.protobuf.InvalidProtocolBufferException {return PARSER.parseFrom(data, extensionRegistry);}public static StudentPOJO.Student parseFrom(byte[] data)throws com.google.protobuf.InvalidProtocolBufferException {return PARSER.parseFrom(data);}public static StudentPOJO.Student parseFrom(byte[] data,com.google.protobuf.ExtensionRegistryLite extensionRegistry)throws com.google.protobuf.InvalidProtocolBufferException {return PARSER.parseFrom(data, extensionRegistry);}public static StudentPOJO.Student parseFrom(java.io.InputStream input)throws java.io.IOException {return com.google.protobuf.GeneratedMessageV3.parseWithIOException(PARSER, input);}public static StudentPOJO.Student parseFrom(java.io.InputStream input,com.google.protobuf.ExtensionRegistryLite extensionRegistry)throws java.io.IOException {return com.google.protobuf.GeneratedMessageV3.parseWithIOException(PARSER, input, extensionRegistry);}public static StudentPOJO.Student parseDelimitedFrom(java.io.InputStream input)throws java.io.IOException {return com.google.protobuf.GeneratedMessageV3.parseDelimitedWithIOException(PARSER, input);}public static StudentPOJO.Student parseDelimitedFrom(java.io.InputStream input,com.google.protobuf.ExtensionRegistryLite extensionRegistry)throws java.io.IOException {return com.google.protobuf.GeneratedMessageV3.parseDelimitedWithIOException(PARSER, input, extensionRegistry);}public static StudentPOJO.Student parseFrom(com.google.protobuf.CodedInputStream input)throws java.io.IOException {return com.google.protobuf.GeneratedMessageV3.parseWithIOException(PARSER, input);}public static StudentPOJO.Student parseFrom(com.google.protobuf.CodedInputStream input,com.google.protobuf.ExtensionRegistryLite extensionRegistry)throws java.io.IOException {return com.google.protobuf.GeneratedMessageV3.parseWithIOException(PARSER, input, extensionRegistry);}@java.lang.Overridepublic Builder newBuilderForType() { return newBuilder(); }public static Builder newBuilder() {return DEFAULT_INSTANCE.toBuilder();}public static Builder newBuilder(StudentPOJO.Student prototype) {return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);}@java.lang.Overridepublic Builder toBuilder() {return this == DEFAULT_INSTANCE? new Builder() : new Builder().mergeFrom(this);}@java.lang.Overrideprotected Builder newBuilderForType(com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {Builder builder = new Builder(parent);return builder;}/*** <pre>*会在 StudentPOJO 外部类生成一个内部类 Student, 他是真正发送的POJO对象* </pre>** Protobuf type {@code Student}*/public static final class Builder extendscom.google.protobuf.GeneratedMessageV3.Builder<Builder> implements// @@protoc_insertion_point(builder_implements:Student)StudentPOJO.StudentOrBuilder {public static final com.google.protobuf.Descriptors.DescriptorgetDescriptor() {return StudentPOJO.internal_static_Student_descriptor;}@java.lang.Overrideprotected com.google.protobuf.GeneratedMessageV3.FieldAccessorTableinternalGetFieldAccessorTable() {return StudentPOJO.internal_static_Student_fieldAccessorTable.ensureFieldAccessorsInitialized(StudentPOJO.Student.class, StudentPOJO.Student.Builder.class);}// Construct using StudentPOJO.Student.newBuilder()private Builder() {maybeForceBuilderInitialization();}private Builder(com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {super(parent);maybeForceBuilderInitialization();}private void maybeForceBuilderInitialization() {if (com.google.protobuf.GeneratedMessageV3.alwaysUseFieldBuilders) {}}@java.lang.Overridepublic Builder clear() {super.clear();id_ = 0;name_ = "";return this;}@java.lang.Overridepublic com.google.protobuf.Descriptors.DescriptorgetDescriptorForType() {return StudentPOJO.internal_static_Student_descriptor;}@java.lang.Overridepublic StudentPOJO.Student getDefaultInstanceForType() {return StudentPOJO.Student.getDefaultInstance();}@java.lang.Overridepublic StudentPOJO.Student build() {StudentPOJO.Student result = buildPartial();if (!result.isInitialized()) {throw newUninitializedMessageException(result);}return result;}@java.lang.Overridepublic StudentPOJO.Student buildPartial() {StudentPOJO.Student result = new StudentPOJO.Student(this);result.id_ = id_;result.name_ = name_;onBuilt();return result;}@java.lang.Overridepublic Builder clone() {return (Builder) super.clone();}@java.lang.Overridepublic Builder setField(com.google.protobuf.Descriptors.FieldDescriptor field,java.lang.Object value) {return (Builder) super.setField(field, value);}@java.lang.Overridepublic Builder clearField(com.google.protobuf.Descriptors.FieldDescriptor field) {return (Builder) super.clearField(field);}@java.lang.Overridepublic Builder clearOneof(com.google.protobuf.Descriptors.OneofDescriptor oneof) {return (Builder) super.clearOneof(oneof);}@java.lang.Overridepublic Builder setRepeatedField(com.google.protobuf.Descriptors.FieldDescriptor field,int index, java.lang.Object value) {return (Builder) super.setRepeatedField(field, index, value);}@java.lang.Overridepublic Builder addRepeatedField(com.google.protobuf.Descriptors.FieldDescriptor field,java.lang.Object value) {return (Builder) super.addRepeatedField(field, value);}@java.lang.Overridepublic Builder mergeFrom(com.google.protobuf.Message other) {if (other instanceof StudentPOJO.Student) {return mergeFrom((StudentPOJO.Student)other);} else {super.mergeFrom(other);return this;}}public Builder mergeFrom(StudentPOJO.Student other) {if (other == StudentPOJO.Student.getDefaultInstance()) return this;if (other.getId() != 0) {setId(other.getId());}if (!other.getName().isEmpty()) {name_ = other.name_;onChanged();}this.mergeUnknownFields(other.unknownFields);onChanged();return this;}@java.lang.Overridepublic final boolean isInitialized() {return true;}@java.lang.Overridepublic Builder mergeFrom(com.google.protobuf.CodedInputStream input,com.google.protobuf.ExtensionRegistryLite extensionRegistry)throws java.io.IOException {StudentPOJO.Student parsedMessage = null;try {parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);} catch (com.google.protobuf.InvalidProtocolBufferException e) {parsedMessage = (StudentPOJO.Student) e.getUnfinishedMessage();throw e.unwrapIOException();} finally {if (parsedMessage != null) {mergeFrom(parsedMessage);}}return this;}private int id_ ;/*** <pre>* Student 类中有 一个属性 名字为 id 类型为int32(protobuf类型) 1表示属性序号,不是值* </pre>** <code>int32 id = 1;</code>*/public int getId() {return id_;}/*** <pre>* Student 类中有 一个属性 名字为 id 类型为int32(protobuf类型) 1表示属性序号,不是值* </pre>** <code>int32 id = 1;</code>*/public Builder setId(int value) {id_ = value;onChanged();return this;}/*** <pre>* Student 类中有 一个属性 名字为 id 类型为int32(protobuf类型) 1表示属性序号,不是值* </pre>** <code>int32 id = 1;</code>*/public Builder clearId() {id_ = 0;onChanged();return this;}private java.lang.Object name_ = "";/*** <code>string name = 2;</code>*/public java.lang.String getName() {java.lang.Object ref = name_;if (!(ref instanceof java.lang.String)) {com.google.protobuf.ByteString bs =(com.google.protobuf.ByteString) ref;java.lang.String s = bs.toStringUtf8();name_ = s;return s;} else {return (java.lang.String) ref;}}/*** <code>string name = 2;</code>*/public com.google.protobuf.ByteStringgetNameBytes() {java.lang.Object ref = name_;if (ref instanceof String) {com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8((java.lang.String) ref);name_ = b;return b;} else {return (com.google.protobuf.ByteString) ref;}}/*** <code>string name = 2;</code>*/public Builder setName(java.lang.String value) {if (value == null) {throw new NullPointerException();}name_ = value;onChanged();return this;}/*** <code>string name = 2;</code>*/public Builder clearName() {name_ = getDefaultInstance().getName();onChanged();return this;}/*** <code>string name = 2;</code>*/public Builder setNameBytes(com.google.protobuf.ByteString value) {if (value == null) {throw new NullPointerException();}checkByteStringIsUtf8(value);name_ = value;onChanged();return this;}@java.lang.Overridepublic final Builder setUnknownFields(final com.google.protobuf.UnknownFieldSet unknownFields) {return super.setUnknownFieldsProto3(unknownFields);}@java.lang.Overridepublic final Builder mergeUnknownFields(final com.google.protobuf.UnknownFieldSet unknownFields) {return super.mergeUnknownFields(unknownFields);}// @@protoc_insertion_point(builder_scope:Student)}// @@protoc_insertion_point(class_scope:Student)private static final StudentPOJO.Student DEFAULT_INSTANCE;static {DEFAULT_INSTANCE = new StudentPOJO.Student();}public static StudentPOJO.Student getDefaultInstance() {return DEFAULT_INSTANCE;}private static final com.google.protobuf.Parser<Student>PARSER = new com.google.protobuf.AbstractParser<Student>() {@java.lang.Overridepublic Student parsePartialFrom(com.google.protobuf.CodedInputStream input,com.google.protobuf.ExtensionRegistryLite extensionRegistry)throws com.google.protobuf.InvalidProtocolBufferException {return new Student(input, extensionRegistry);}};public static com.google.protobuf.Parser<Student> parser() {return PARSER;}@java.lang.Overridepublic com.google.protobuf.Parser<Student> getParserForType() {return PARSER;}@java.lang.Overridepublic StudentPOJO.Student getDefaultInstanceForType() {return DEFAULT_INSTANCE;}}private static final com.google.protobuf.Descriptors.Descriptorinternal_static_Student_descriptor;private static final com.google.protobuf.GeneratedMessageV3.FieldAccessorTableinternal_static_Student_fieldAccessorTable;public static com.google.protobuf.Descriptors.FileDescriptorgetDescriptor() {return descriptor;}private static com.google.protobuf.Descriptors.FileDescriptordescriptor;static {java.lang.String[] descriptorData = {"\n\rStudent.proto\"#\n\007Student\022\n\n\002id\030\001 \001(\005\022\014" +"\n\004name\030\002 \001(\tB\rB\013StudentPOJOb\006proto3"};com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =new com.google.protobuf.Descriptors.FileDescriptor. InternalDescriptorAssigner() {public com.google.protobuf.ExtensionRegistry assignDescriptors(com.google.protobuf.Descriptors.FileDescriptor root) {descriptor = root;return null;}};com.google.protobuf.Descriptors.FileDescriptor.internalBuildGeneratedFileFrom(descriptorData,new com.google.protobuf.Descriptors.FileDescriptor[] {}, assigner);internal_static_Student_descriptor =getDescriptor().getMessageTypes().get(0);internal_static_Student_fieldAccessorTable = newcom.google.protobuf.GeneratedMessageV3.FieldAccessorTable(internal_static_Student_descriptor,new java.lang.String[] { "Id", "Name", });}// @@protoc_insertion_point(outer_class_scope)
}
1.2 NettyServer.java
@Slf4j
public class NettyServer {public static void main(String[] args) {NioEventLoopGroup bossGroup = new NioEventLoopGroup(1);NioEventLoopGroup workerGroup = new NioEventLoopGroup();try {ServerBootstrap serverBootstrap = new ServerBootstrap();serverBootstrap.group(bossGroup,workerGroup).channel(NioServerSocketChannel.class).option(ChannelOption.SO_BACKLOG,128).childOption(ChannelOption.SO_KEEPALIVE,true).childHandler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {ChannelPipeline pipeline = ch.pipeline();pipeline.addLast("decoder",new ProtobufDecoder(StudentPOJO.Student.getDefaultInstance()));pipeline.addLast(new NettyServerHandler());}});ChannelFuture channelFuture = serverBootstrap.bind(8000).sync();channelFuture.addListener(new ChannelFutureListener() {@Overridepublic void operationComplete(ChannelFuture future) throws Exception {if(future.isSuccess()){log.info("监听端口 8000成功");}else{log.info("监听端口 8000失败");}}});channelFuture.channel().closeFuture().sync();}catch (Exception e){}finally {bossGroup.shutdownGracefully();workerGroup.shutdownGracefully();}}
}
1.3 NettyServerHandler.java
@Slf4j
public class NettyServerHandler extends SimpleChannelInboundHandler<StudentPOJO.Student> {//读取实际数据@Overrideprotected void channelRead0(ChannelHandlerContext ctx, StudentPOJO.Student msg) throws Exception {log.info("客户端发送的数据,id:{},名字是:{}",msg.getId(),msg.getName());}//读取数据后,将数据写入缓存并刷新@Overridepublic void channelReadComplete(ChannelHandlerContext ctx) throws Exception {ctx.writeAndFlush(Unpooled.copiedBuffer("hello, 客户端", CharsetUtil.UTF_8));}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {cause.printStackTrace();ctx.close();}
}
1.4 NettyClient.java
public class NettyClient {public static void main(String[] args) {NioEventLoopGroup eventLoopGroup = new NioEventLoopGroup();try {Bootstrap bootstrap = new Bootstrap();bootstrap.group(eventLoopGroup).channel(NioSocketChannel.class).handler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {ChannelPipeline pipeline = ch.pipeline();pipeline.addLast(new ProtobufEncoder());pipeline.addLast(new NettyClientHandler());}});ChannelFuture channelFuture = bootstrap.connect("127.0.0.1", 8000).sync();channelFuture.channel().closeFuture().sync();}catch (Exception e){e.printStackTrace();}finally {eventLoopGroup.shutdownGracefully();}}
}
1.5 NettyClientHandler.java
@Slf4j
public class NettyClientHandler extends ChannelInboundHandlerAdapter {//当通道就绪后就会触发这个方法@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception {StudentPOJO.Student student = StudentPOJO.Student.newBuilder().setId(1001).setName("唐僧").build();ctx.writeAndFlush(student);}//当通道有读取事件时,会触发这个方法@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {ByteBuf buf = (ByteBuf) msg;log.info("服务器回复的消息是:{}",buf.toString(CharsetUtil.UTF_8));log.info("服务器的地址是:{}",ctx.channel().remoteAddress());}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {cause.printStackTrace();ctx.close();}
}
1.6 运行结果
服务端
客户端