1:Protocol Buffers介绍
Protocol Buffers(Protobuf)是Google推出的语言无关,平台无关的可扩展机制,用于序列化结构数据。由于是一种二进制的序列化协议,并且数据结构做了相应优化,因此比传统的XML、JSON数据格式序列化后体积更小,传输更快。Protobuf有proto2和proto3两个版本,有着不同的数据格式定义,proto3更简单,支持更多的编程语言,在这里我们使用proto3版本。Protobuf使用了一个编译器,可根据.proto文件中定义的数据结构,自动生成各种语言的模板代码,方便使用。
2:在netty中使用多Protocol Buffer协议
//配置Protobuf解码处理器,消息接收到了就会自动解码,ProtobufDecoder是netty自带的,Message是自己定义的Protobuf类
pipeline.addLast("protobufDecoder",new ProtobufDecoder(AIConstructionProtobuf.ParentMessage.getDefaultInstance()));
在netty中使用Protocol Buffer,有一个不足之处、Handler只能处理一种特定的类型,解码处是一个类,而我们的项目中又不可能只有一种类型,一个类,不可能写成Object类型,于是我们需要抽象一个Parent的对象。在每一帧数据里面增加一个 DataType类型。来统一解析。
syntax ="proto3";
package com.tieniu.miao.netty.sixthexample;
option optimize_for = SPEED;
option java_package = "com.tieniu.miao.netty.seventhexample";
option java_outer_classname="MyDataInfo";
message MyMessage {
enum DataType{
PeopleType = 0;
DogType = 1;
CatType = 2;
}
DataType data_type = 0;
//oneof的意思:如果有多个可选字段,在某一个时刻只能只有一个值被设置,可以节省内存空间
oneof dataBody {
People people = 1;
Dog dog = 2;
Cat cat = 3;
}
}
message People{
optional string name = 1;
optional int32 age = 2;
optional string address = 3;
}
message Dog{
optional string name = 1;
optional string age = 2;
}
message Cat{
optional string name = 1;
optional string city = 2;
}
3:生成Java代码、把Mes.proto文件放到 create.cmd 同文件下、双击 create.cmd 下。即可生成java文件。
4:配置代码
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.yuyuan.internet.modules.video.protobufvo.AIConstructionProtobuf;
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;
import io.netty.handler.timeout.IdleStateHandler;
import io.netty.util.HashedWheelTimer;
import io.netty.util.Timer;
/**
* netty处理器配置
* @author kokJuis
* @version 1.0
* @date 2016-9-30
*/
public class VideoServerInitializer extends ChannelInitializer<SocketChannel> {
static Logger logger = LoggerFactory.getLogger(VideoServerInitializer.class);
Timer timer;
public VideoServerInitializer() {
timer = new HashedWheelTimer();
}
@Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
// ----Protobuf处理器,这里的配置是关键----
pipeline.addLast("frameDecoder", new ProtobufVarint32FrameDecoder());// 用于decode前解决半包和粘包问题(利用包头中的包含数组长度来识别半包粘包)
//配置Protobuf解码处理器,消息接收到了就会自动解码,ProtobufDecoder是netty自带的,Message是自己定义的Protobuf类
pipeline.addLast("protobufDecoder",new ProtobufDecoder(MyDataInfo.ParentMessage.getDefaultInstance()));
// 用于在序列化的字节数组前加上一个简单的包头,只包含序列化的字节长度。
pipeline.addLast("frameEncoder",new ProtobufVarint32LengthFieldPrepender());
//配置Protobuf编码器,发送的消息会先经过编码
pipeline.addLast("protobufEncoder", new ProtobufEncoder());
// ----Protobuf处理器END----
pipeline.addLast("handler", new VideoServerHandler());//自己定义的消息处理器,接收消息会在这个类处理
//pipeline.addLast("ackHandler", new AckServerHandler());//处理ACK
pipeline.addLast("timeout", new IdleStateHandler(100, 0, 0,TimeUnit.SECONDS));//此两项为添加心跳机制,60秒查看一次在线的客户端channel是否空闲
pipeline.addLast(new HeartBeatServerHandler());// 心跳处理handler
}
// pipeline.addLast("framer", new DelimiterBasedFrameDecoder(2 * 1024, Delimiters.lineDelimiter()));
// pipeline.addLast("decoder", new StringDecoder(CharsetUtil.UTF_8));
// pipeline.addLast("encoder", new StringEncoder(CharsetUtil.UTF_8));
}