2021SC@SDUSC
Google Protobuf
1 basic introduction of encoding and decoding
-
When writing a network application, because the data transmitted in the network is binary bytecode data, it needs to be encoded when sending data and decoded when receiving data [schematic diagram]
-
There are two components of codec: decoder and encoder. The encoder is responsible for converting business data into bytecode data, and the decoder is responsible for converting bytecode data into business data
2 Analysis of the encoding and decoding mechanism and problems of netty itself
-
Netty itself provides some codec (codec)
-
Encoder provided by Netty
StringEncoder, which encodes string data
ObjectEncoder, which encodes Java objects
... -
Decoder provided by Netty
StringDecoder, which decodes string data
ObjectDecoder to decode Java objects
... -
The ObjectDecoder and ObjectEncoder provided by Netty can be used to encode and decode POJO objects or various business objects. Java serialization technology is still used at the bottom, but the efficiency of Java serialization technology is not high. There are the following problems
- Cannot cross language
- The volume of serialized object is too large, which is more than 5 times that of binary coding.
- Serialization performance is too low
- =>Lead to a new solution [Google's Protobuf]
3 Protobuf
-
Protobuf basic introduction and use diagram
-
Protobuf fer is an open source project released by Google. Its full name is Google Protocol Buffers. It is a lightweight and efficient structured data storage format that can be used for structured data serialization or serialization. It is very suitable for data storage or RPC [remote procedure call] data exchange format.
At present, many companies transform http+json into tcp+protobuf, which is very efficient -
Reference documents: https://developers.google.cn/protocol-buffers/docs/reference/overview?hl=zh-cn Language Guide
-
Protobuf manages data in the form of message
-
Support cross platform and cross language, i.e. [client and server can be written in different languages] (support most current languages, such as C + +, c#, Java, python, etc.)
-
High performance, high reliability
-
The Protobuf compiler can automatically generate code, and Protobuf uses the definition of classes Proto file. Description, written in idea When the proto file is, it will automatically prompt whether to download it Write plugins using ptotot You can highlight the syntax.
-
Then through protocol Exe compiler according to proto is automatically generated java file
-
Schematic diagram of protobuf use
4 example of protobuf quick start
Write a program and use Protobuf to complete the following functions
- The client can send a Student PoJo object to the server (encoded by Protobuf)
- The server can receive the Student PoJo object and display the information (decoded by Protobuf)
Step 1: introduce Protobuf coordinates into Maven project and download relevant jar packages
pom.xml (note that different versions have different specifications)
<dependencies> <dependency> <groupId>com.google.protobuf</groupId> <artifactId>protobuf-java</artifactId> <version>3.6.1</version> <scope>compile</scope> </dependency> </dependencies>
Step 2: write the proto file Student,proto
syntax = "proto3"; //edition option java_outer_classname = "StudentPOJO";//The generated external class name is also the file name //protobuf uses message to manage data message Student { //An internal class Student will be generated in the external class of StudentPOJO, which is the real sent POJO object int32 id = 1; // In the Student class, there is an attribute whose name is id and type is int32(protobuf type). 1 represents the attribute sequence number, not the value string name = 2; }
int32
NettyClient
package com.shandonguniversity.netty.codec; import io.netty.bootstrap.Bootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.codec.protobuf.ProtobufEncoder; public class NettyClient { public static void main(String[] args) throws Exception { //The client needs an event loop group EventLoopGroup group = new NioEventLoopGroup(); try { //Create client startup object //Note that the client uses Bootstrap instead of ServerBootstrap Bootstrap bootstrap = new Bootstrap(); //Set relevant parameters bootstrap.group(group) //Set thread group .channel(NioSocketChannel.class) // Set the implementation class of the client channel (reflection) .handler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); //Add ProtoBufEncoder to pipeline pipeline.addLast("encoder", new ProtobufEncoder()); pipeline.addLast(new NettyClientHandler()); //Add your own processor } }); System.out.println("client ok.."); //Start the client to connect to the server //The analysis of ChannelFuture involves the asynchronous model of netty ChannelFuture channelFuture = bootstrap.connect("127.0.0.1", 6668).sync(); //Monitor closed channels channelFuture.channel().closeFuture().sync(); }finally { group.shutdownGracefully(); } } }
NettyServer
package com.shandonguniversity.netty.codec; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.*; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.handler.codec.protobuf.ProtobufDecoder; public class NettyServer { public static void main(String[] args) throws Exception { //Create BossGroup and WorkerGroup //explain //1. Create two thread groups, bossGroup and workerGroup //2. The bossgroup only handles connection requests. The real and client business processing will be handed over to the workerGroup //3. Both are infinite loops //4. Number of sub threads (NioEventLoop) contained in bossgroup and workerGroup // Default actual cpu cores * 2 EventLoopGroup bossGroup = new NioEventLoopGroup(1); EventLoopGroup workerGroup = new NioEventLoopGroup(); //8 try { //Create a server-side startup object and configure parameters ServerBootstrap bootstrap = new ServerBootstrap(); //Use chain programming to set bootstrap.group(bossGroup, workerGroup) //Set up two thread groups .channel(NioServerSocketChannel.class) //NioSocketChannel is used as the channel implementation of the server .option(ChannelOption.SO_BACKLOG, 128) // Set the number of connections obtained from the thread queue .childOption(ChannelOption.SO_KEEPALIVE, true) //Set keep active connection state // . handler(null) / / this handler corresponds to bossgroup and childhandler corresponds to workerGroup .childHandler(new ChannelInitializer<SocketChannel>() {//Create a channel initialization object (anonymous object) //Set processor for pipeline @Override protected void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); //Add ProtoBufDecoder to pipeline //Specifies which object to decode pipeline.addLast("decoder", new ProtobufDecoder(StudentPOJO.Student.getDefaultInstance())); pipeline.addLast(new NettyServerHandler()); } }); // Set the processor for the pipeline corresponding to the EventLoop of our workerGroup System.out.println(".....The server is ready..."); //Bind a port and synchronize to generate a ChannelFuture object //Start the server (and bind the port) ChannelFuture cf = bootstrap.bind(6668).sync(); //Register a listener for cf to monitor events we care about cf.addListener(new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture future) throws Exception { if (cf.isSuccess()) { System.out.println("Listening port 6668 succeeded"); } else { System.out.println("Listening port 6668 failed"); } } }); //Monitor closed channels cf.channel().closeFuture().sync(); }finally { bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } } }
StudentPOJO
package com.shandonguniversity.netty.codec;// Generated by the protocol buffer compiler. DO NOT EDIT! // source: Student.proto public 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 There is an attribute in the class whose name is id and type is int32(protobuf type). 1 represents the attribute sequence number, not the value * </pre> * * <code>int32 id = 1;</code> */ int getId(); /** * <code>string name = 2;</code> */ String getName(); /** * <code>string name = 2;</code> */ com.google.protobuf.ByteString getNameBytes(); } /** * <pre> *protobuf Managing data using message * </pre> * * Protobuf type {@code Student} */ public static final class Student extends com.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_ = ""; } @Override public final com.google.protobuf.UnknownFieldSet getUnknownFields() { 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 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: { 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.Descriptor getDescriptor() { return StudentPOJO.internal_static_Student_descriptor; } @Override protected FieldAccessorTable internalGetFieldAccessorTable() { return StudentPOJO.internal_static_Student_fieldAccessorTable .ensureFieldAccessorsInitialized( Student.class, Builder.class); } public static final int ID_FIELD_NUMBER = 1; private int id_; /** * <pre> * Student There is an attribute in the class whose name is id and type is int32(protobuf type). 1 represents the attribute sequence number, not the value * </pre> * * <code>int32 id = 1;</code> */ public int getId() { return id_; } public static final int NAME_FIELD_NUMBER = 2; private volatile Object name_; /** * <code>string name = 2;</code> */ public String getName() { Object ref = name_; if (ref instanceof String) { return (String) ref; } else { com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; String s = bs.toStringUtf8(); name_ = s; return s; } } /** * <code>string name = 2;</code> */ public com.google.protobuf.ByteString getNameBytes() { Object ref = name_; if (ref instanceof String) { com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (String) ref); name_ = b; return b; } else { return (com.google.protobuf.ByteString) ref; } } private byte memoizedIsInitialized = -1; @Override public final boolean isInitialized() { byte isInitialized = memoizedIsInitialized; if (isInitialized == 1) return true; if (isInitialized == 0) return false; memoizedIsInitialized = 1; return true; } @Override public 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); } @Override public 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; } @Override public boolean equals(final Object obj) { if (obj == this) { return true; } if (!(obj instanceof Student)) { return super.equals(obj); } Student other = (Student) obj; boolean result = true; result = result && (getId() == other.getId()); result = result && getName() .equals(other.getName()); result = result && unknownFields.equals(other.unknownFields); return result; } @Override public 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 Student parseFrom( java.nio.ByteBuffer data) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data); } public static Student parseFrom( java.nio.ByteBuffer data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data, extensionRegistry); } public static Student parseFrom( com.google.protobuf.ByteString data) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data); } public static Student parseFrom( com.google.protobuf.ByteString data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data, extensionRegistry); } public static Student parseFrom(byte[] data) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data); } public static Student parseFrom( byte[] data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data, extensionRegistry); } public static Student parseFrom(java.io.InputStream input) throws java.io.IOException { return com.google.protobuf.GeneratedMessageV3 .parseWithIOException(PARSER, input); } public static 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 Student parseDelimitedFrom(java.io.InputStream input) throws java.io.IOException { return com.google.protobuf.GeneratedMessageV3 .parseDelimitedWithIOException(PARSER, input); } public static 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 Student parseFrom( com.google.protobuf.CodedInputStream input) throws java.io.IOException { return com.google.protobuf.GeneratedMessageV3 .parseWithIOException(PARSER, input); } public static 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); } @Override public Builder newBuilderForType() { return newBuilder(); } public static Builder newBuilder() { return DEFAULT_INSTANCE.toBuilder(); } public static Builder newBuilder(Student prototype) { return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); } @Override public Builder toBuilder() { return this == DEFAULT_INSTANCE ? new Builder() : new Builder().mergeFrom(this); } @Override protected Builder newBuilderForType( BuilderParent parent) { Builder builder = new Builder(parent); return builder; } /** * <pre> *protobuf Managing data using message * </pre> * * Protobuf type {@code Student} */ public static final class Builder extends com.google.protobuf.GeneratedMessageV3.Builder<Builder> implements // @@protoc_insertion_point(builder_implements:Student) StudentOrBuilder { public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { return StudentPOJO.internal_static_Student_descriptor; } @Override protected FieldAccessorTable internalGetFieldAccessorTable() { return StudentPOJO.internal_static_Student_fieldAccessorTable .ensureFieldAccessorsInitialized( Student.class, Builder.class); } // Construct using StudentPOJO.Student.newBuilder() private Builder() { maybeForceBuilderInitialization(); } private Builder( BuilderParent parent) { super(parent); maybeForceBuilderInitialization(); } private void maybeForceBuilderInitialization() { if (com.google.protobuf.GeneratedMessageV3 .alwaysUseFieldBuilders) { } } @Override public Builder clear() { super.clear(); id_ = 0; name_ = ""; return this; } @Override public com.google.protobuf.Descriptors.Descriptor getDescriptorForType() { return StudentPOJO.internal_static_Student_descriptor; } @Override public Student getDefaultInstanceForType() { return Student.getDefaultInstance(); } @Override public Student build() { Student result = buildPartial(); if (!result.isInitialized()) { throw newUninitializedMessageException(result); } return result; } @Override public Student buildPartial() { Student result = new Student(this); result.id_ = id_; result.name_ = name_; onBuilt(); return result; } @Override public Builder clone() { return (Builder) super.clone(); } @Override public Builder setField( com.google.protobuf.Descriptors.FieldDescriptor field, Object value) { return (Builder) super.setField(field, value); } @Override public Builder clearField( com.google.protobuf.Descriptors.FieldDescriptor field) { return (Builder) super.clearField(field); } @Override public Builder clearOneof( com.google.protobuf.Descriptors.OneofDescriptor oneof) { return (Builder) super.clearOneof(oneof); } @Override public Builder setRepeatedField( com.google.protobuf.Descriptors.FieldDescriptor field, int index, Object value) { return (Builder) super.setRepeatedField(field, index, value); } @Override public Builder addRepeatedField( com.google.protobuf.Descriptors.FieldDescriptor field, Object value) { return (Builder) super.addRepeatedField(field, value); } @Override public Builder mergeFrom(com.google.protobuf.Message other) { if (other instanceof Student) { return mergeFrom((Student)other); } else { super.mergeFrom(other); return this; } } public Builder mergeFrom(Student other) { if (other == 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; } @Override public final boolean isInitialized() { return true; } @Override public Builder mergeFrom( com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { Student parsedMessage = null; try { parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); } catch (com.google.protobuf.InvalidProtocolBufferException e) { parsedMessage = (Student) e.getUnfinishedMessage(); throw e.unwrapIOException(); } finally { if (parsedMessage != null) { mergeFrom(parsedMessage); } } return this; } private int id_ ; /** * <pre> * Student There is an attribute in the class whose name is id and type is int32(protobuf type). 1 represents the attribute sequence number, not the value * </pre> * * <code>int32 id = 1;</code> */ public int getId() { return id_; } /** * <pre> * Student There is an attribute in the class whose name is id and type is int32(protobuf type). 1 represents the attribute sequence number, not the value * </pre> * * <code>int32 id = 1;</code> */ public Builder setId(int value) { id_ = value; onChanged(); return this; } /** * <pre> * Student There is an attribute in the class whose name is id and type is int32(protobuf type). 1 represents the attribute sequence number, not the value * </pre> * * <code>int32 id = 1;</code> */ public Builder clearId() { id_ = 0; onChanged(); return this; } private Object name_ = ""; /** * <code>string name = 2;</code> */ public String getName() { Object ref = name_; if (!(ref instanceof String)) { com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; String s = bs.toStringUtf8(); name_ = s; return s; } else { return (String) ref; } } /** * <code>string name = 2;</code> */ public com.google.protobuf.ByteString getNameBytes() { Object ref = name_; if (ref instanceof String) { com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (String) ref); name_ = b; return b; } else { return (com.google.protobuf.ByteString) ref; } } /** * <code>string name = 2;</code> */ public Builder setName( 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; } @Override public final Builder setUnknownFields( final com.google.protobuf.UnknownFieldSet unknownFields) { return super.setUnknownFieldsProto3(unknownFields); } @Override public 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 Student DEFAULT_INSTANCE; static { DEFAULT_INSTANCE = new Student(); } public static Student getDefaultInstance() { return DEFAULT_INSTANCE; } private static final com.google.protobuf.Parser<Student> PARSER = new com.google.protobuf.AbstractParser<Student>() { @Override public 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; } @Override public com.google.protobuf.Parser<Student> getParserForType() { return PARSER; } @Override public Student getDefaultInstanceForType() { return DEFAULT_INSTANCE; } } private static final com.google.protobuf.Descriptors.Descriptor internal_static_Student_descriptor; private static final com.google.protobuf.GeneratedMessageV3.FieldAccessorTable internal_static_Student_fieldAccessorTable; public static com.google.protobuf.Descriptors.FileDescriptor getDescriptor() { return descriptor; } private static com.google.protobuf.Descriptors.FileDescriptor descriptor; static { 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 = new com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( internal_static_Student_descriptor, new String[] { "Id", "Name", }); } // @@protoc_insertion_point(outer_class_scope) }
NettyClientHandler
package com.shandonguniversity.netty.codec; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.util.CharsetUtil; public class NettyClientHandler extends ChannelInboundHandlerAdapter { //This method is triggered when the channel is ready @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { //A Student object to the server occurred StudentPOJO.Student student = StudentPOJO.Student.newBuilder().setId(4).setName("Zhi duoxing Wu Yong").build(); //Teacher , Member ,Message ctx.writeAndFlush(student); } //Triggered when the channel has a read event @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { ByteBuf buf = (ByteBuf) msg; System.out.println("Message from server reply:" + buf.toString(CharsetUtil.UTF_8)); System.out.println("Server address: "+ ctx.channel().remoteAddress()); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); ctx.close(); } }
NettyServerHandler
package com.shandonguniversity.netty.codec; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.*; import io.netty.util.CharsetUtil; /* explain 1. To customize a Handler, we need to continue with a handleradapter (specification) specified by netty 2. At this time, we can customize a handler to be called a handler */ //public class NettyServerHandler extends ChannelInboundHandlerAdapter { public class NettyServerHandler extends SimpleChannelInboundHandler<StudentPOJO.Student> { //Read the actual data (here we can read the messages sent by the client) /* 1. ChannelHandlerContext ctx:Context object, containing pipeline, channel and address 2. Object msg: This is the default Object for data sent by the client */ @Override public void channelRead0(ChannelHandlerContext ctx, StudentPOJO.Student msg) throws Exception { //Read the studentpojo.com sent from the client Student System.out.println("Data sent by client id=" + msg.getId() + " name=" + msg.getName()); } // //Read the actual data (here we can read the messages sent by the client) // /* // 1. ChannelHandlerContext ctx:Context object, containing pipeline, channel and address // 2. Object msg: This is the default Object for data sent by the client // */ // @Override // public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { // // //Read the studentpojo.com sent from the client Student // // StudentPOJO.Student student = (StudentPOJO.Student) msg; // // System.out.println("data sent by client id=" + student.getId() + "name =" + student getName()); // } //Data read complete @Override public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { //writeAndFlush is write + flush //Writes data to the cache and flushes //Generally speaking, we encode the transmitted data ctx.writeAndFlush(Unpooled.copiedBuffer("hello, client~(>^ω^<)Meow 1", CharsetUtil.UTF_8)); } //To handle exceptions, it is generally necessary to close the channel @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { ctx.close(); } }