Protocol Buffer整合netty
阿新 • • 發佈:2020-12-18
技術標籤:Netty
Protocol Buffer整合netty
1-1 前言
我們是在學習netty的背景下,學些protocol Buffer的,所以我們在我們的實踐文件,也是在這樣的背景下整理出來的。
1-2 編輯簡單的Proco檔案
1-2-1 Student .proto
syntax = "proto2";
package com.zt.proto;
option optimize_for = SPEED;
option java_package = "com.zt.proto";
option java_outer_classname = "MyDataInfo";
message Person {
required string name =1;
optional int32 age=2;
optional string address=3;
}
-
syntax :指定使用的proto的版本 我們這裡使用的是proto2
-
package :指定生成的java的類的包路徑,如果 java_package不指定,就是這個目錄
-
optimize_for:檔案級別的選項,Protocol Buffer定義三種優化級別SPEED/CODE_SIZE/LITE_RUNTIME。預設情況下是SPEED
-
SPEED:表示生成的程式碼執行效率高,但是由此生成的程式碼編譯後會佔用更多的空間。
-
CODE_SIZE: 和SPEED恰恰相反,程式碼執行效率較低,但是由此生成的程式碼編譯後會佔用更少的空間,通常用於資源有限的平臺,如Mobile。
-
LITE_RUNTIME: 生成的程式碼執行效率高,同時生成程式碼編譯後的所佔用的空間也是非常少。這是以犧牲Protocol Buffer提供的反射功能為代價的。因此我們在C++中連結Protocol Buffer庫時僅需連結libprotobuf-lite,而非libprotobuf。在Java中僅需包含protobuf-java-2.4.1-lite.jar,而非protobuf-java-2.4.1.jar。
-
java_package :表示生成的java類的包路徑,官方建議,我們在編輯proto檔案到額時候,最好還是指定。
-
java_outer_classname :表示生成的Java類的類名
-
message :指定一個訊息協議
-
required:表示在傳輸資料的的時候這個欄位為必須傳輸的資料。
-
optional:對應required,可選輸出資料。
-
string 和int32 :還有其他的型別,指定的資料的型別
可以在程式除錯階段使用 SPEED模式,而上線以後使用提升效能使用 LITE_RUNTIME 模式優化。
1-2-2 生成Java類和小測試
- 生成的命令
protoc --java_out=src\main\java src\protobuf\Student.proto
-
生成的java類
生成的Java類有點大 這裡就不貼出來。
-
測試小程式
package com.zt.proto;
import com.google.protobuf.InvalidProtocolBufferException;
/**
* @Description:
* @Date: 2020/12/15 10:37
* @author: zt
*/
public class ProtoBufTest {
public static void main(String[] args) throws InvalidProtocolBufferException {
MyDataInfo.Person person = MyDataInfo.Person.newBuilder()
.setName("張山")
.setAge(1111)
.setAddress("成都")
.build();
byte[] bytes = person.toByteArray();
// 位元組陣列可以網路傳輸 實現不同機子的遠端過程呼叫
MyDataInfo.Person person1 = MyDataInfo.Person.parseFrom(bytes);
System.out.println(person1.getAddress());
System.out.println(person1.getAge());
System.out.println(person1.getName());
}
}
- 測試小程式的執行結果
成都
1111
張山
Process finished with exit code 0
1-3 整合netty和proco
1-3-1 proco檔案
syntax = "proto2";
package com.zt.proto;
option optimize_for = SPEED;
option java_package = "com.zt.proto";
option java_outer_classname = "MyDataInfo";
message Person {
required string name =1;
optional int32 age=2;
optional string address=3;
}
1-3-2 netty相關
1-3-2-1 TestServer
package com.zt.proto;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
/**
* @Description:
* @Date: 2020/12/15 10:53
* @author: zt
*/
public class TestServer {
public static void main(String[] args) {
NioEventLoopGroup bossGroup = new NioEventLoopGroup();
NioEventLoopGroup workGroup = new NioEventLoopGroup();
try {
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGroup,workGroup).channel(NioServerSocketChannel.class)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new TestInitializer());
ChannelFuture channelFuture = serverBootstrap.bind(8899).sync();
channelFuture.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
bossGroup.shutdownGracefully();
workGroup.shutdownGracefully();
}
}
}
1-3-2-2 TestInitializer
package com.zt.proto;
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;
/**
* @Description:
* @Date: 2020/12/15 10:59
* @author: zt
*/
public class TestInitializer extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new ProtobufVarint32FrameDecoder());
pipeline.addLast(new ProtobufDecoder(MyDataInfo.Person.getDefaultInstance()));
pipeline.addLast(new ProtobufVarint32LengthFieldPrepender());
// 第一次沒出現Bf shu'xua是ProtobufEncoder
pipeline.addLast(new ProtobufEncoder());
pipeline.addLast(new TestServerHandler());
}
}
1-3-2-3 TestServerHandler
package com.zt.proto;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
/**
* @Description:
* @Date: 2020/12/15 14:27
* @author: zt
*/
public class TestServerHandler extends SimpleChannelInboundHandler<MyDataInfo.Person> {
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, MyDataInfo.Person person) throws Exception {
System.out.println(person.getAddress());
System.out.println(person.getAge());
System.out.println(person.getName());
}
}
1-3-2-4 TestClient
package com.zt.proto;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
/**
* @Description:
* @Date: 2020/12/15 14:28
* @author: zt
*/
public class TestClient {
public static void main(String[] args) {
EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
try {
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(eventLoopGroup).channel(NioSocketChannel.class)
.handler(new TestClientInitializer());
ChannelFuture channelFuture = bootstrap.connect("localhost", 8899).sync();
channelFuture.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
eventLoopGroup.shutdownGracefully();
}
}
}
1-3-2-5 TestClientInitializer
package com.zt.proto;
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;
/**
* @Description:
* @Date: 2020/12/15 14:31
* @author: zt
*/
public class TestClientInitializerextends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new ProtobufVarint32FrameDecoder());
pipeline.addLast(new ProtobufDecoder(MyDataInfo.Person.getDefaultInstance()));
pipeline.addLast(new ProtobufVarint32LengthFieldPrepender());
pipeline.addLast(new ProtobufEncoder());
pipeline.addLast(new TestClientHandler());
}
}
1-3-2-6 TestClientHandler
package com.zt.proto;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
/**
* @Description:
* @Date: 2020/12/15 14:37
* @author: zt
*/
public class TestClientHandler extends SimpleChannelInboundHandler<MyDataInfo.Person> {
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, MyDataInfo.Person person) throws Exception {
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
MyDataInfo.Person person = MyDataInfo.Person.newBuilder()
.setName("張山")
.setAge(1111)
.setAddress("成都")
.build();
ctx.channel().writeAndFlush(person);
System.out.println("TestClientHandler:channelActive");
}
}
1-3-2-7 pom檔案補充
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>ProtocolDemo2</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<!--設定java的編譯的jdk版本-->
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
<protobufJavaVersion>3.11.0</protobufJavaVersion>
<protobufJavaUtilVersion>3.11.0</protobufJavaUtilVersion>
<nettyAllVersion>4.1.40.Final</nettyAllVersion>
</properties>
<dependencies>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>${protobufJavaVersion}</version>
</dependency>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java-util</artifactId>
<version>${protobufJavaUtilVersion}</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>${nettyAllVersion}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
1-3-2-8 簡單說明下
netty相關的點,我這裡就不贅述,前面的文件都有相關的說明。
1-3-3 測試和總結
1-3-3-1 server的日誌
十二月 17, 2020 10:33:53 上午 io.netty.handler.logging.LoggingHandler channelRegistered
資訊: [id: 0x916b2ebf] REGISTERED
十二月 17, 2020 10:33:53 上午 io.netty.handler.logging.LoggingHandler bind
資訊: [id: 0x916b2ebf] BIND: 0.0.0.0/0.0.0.0:8899
十二月 17, 2020 10:33:53 上午 io.netty.handler.logging.LoggingHandler channelActive
資訊: [id: 0x916b2ebf, L:/0:0:0:0:0:0:0:0:8899] ACTIVE
十二月 17, 2020 10:34:04 上午 io.netty.handler.logging.LoggingHandler channelRead
資訊: [id: 0x916b2ebf, L:/0:0:0:0:0:0:0:0:8899] READ: [id: 0x07922e1b, L:/127.0.0.1:8899 - R:/127.0.0.1:59693]
十二月 17, 2020 10:34:04 上午 io.netty.handler.logging.LoggingHandler channelReadComplete
資訊: [id: 0x916b2ebf, L:/0:0:0:0:0:0:0:0:8899] READ COMPLETE
成都
1111
張山
1-3-3-2 client的日誌
TestClientHandler:channelActive
1-3-3-3 總結
- 基本上程式是成功的運行了,我這裡簡單的說明下,在1-2小章節中我們寫了小程式測試下,哪裡我
們是自己編碼和解碼,我們這個整合netty的時候,發現我們沒有解碼和編碼,其實交給了netty幫我
們 處理了。 - 整合netty的大部分還是netty的部分,proco的部分編碼還是沒幾行程式碼。
- 我們這裡是最的資料通訊協議,要是我們存在多種資料通訊協議,我們怎末處理?我會在後面整理出來。