一、應(yīng)用背景:
Protobuf是google 的一種數(shù)據(jù)交換的格式,它獨(dú)立于語言,獨(dú)立于平臺。
優(yōu)點(diǎn):
- json優(yōu)點(diǎn)就是較XML格式更加小巧,傳輸效率較xml提高了很多,可讀性還不錯(cuò)。
- xml優(yōu)點(diǎn)就是可讀性強(qiáng),解析方便。
- protobuf優(yōu)點(diǎn)就是傳輸效率快(據(jù)說在數(shù)據(jù)量大的時(shí)候,傳輸效率比xml和json快10-20倍),序列化后體積相比Json和XML很小,支持跨平臺多語言,消息格式升級和兼容性還不錯(cuò),序列化反序列化速度很快。
缺點(diǎn):
- json缺點(diǎn)就是傳輸效率也不是特別高(比xml快,但比protobuf要慢很多)。
- xml缺點(diǎn)就是效率不高,資源消耗過大。
- protobuf缺點(diǎn)就是使用不太方便。
在一個(gè)需要大量的數(shù)據(jù)傳輸?shù)膱鼍爸校绻麛?shù)據(jù)量很大,那么選擇protobuf可以明顯的減少數(shù)據(jù)量,減少網(wǎng)絡(luò)IO,從而減少網(wǎng)絡(luò)傳輸所消耗的時(shí)間。考慮到作為一個(gè)主打社交的產(chǎn)品,消息數(shù)據(jù)量會非常大,同時(shí)為了節(jié)約流量,所以采用protobuf是一個(gè)不錯(cuò)的選擇。
二、使用
1.引入protobuf庫
pubspec.yaml
...
protobuf: 1.0.1
2.編寫proto文件
socket.message.proto
syntax = "proto3";
package socket;
// 發(fā)送聊天信息
message Message {
string eventId = 1;
string from = 2;
string to = 3;
string createAt = 4;
string type = 5;
string body = 6;
}
// 收到聊天消息
message AckMessage {
string eventId = 1;
}
3.生成proto相關(guān)Model
Terminal
protoc --dart_out=. socket.message.proto
4.編碼、發(fā)消息
a.準(zhǔn)備protobuf對象
Message message = Message();
message.eventId = '####';
message.type = 'text';
message.body = 'hello world';
b.ProtobufUtil編碼
const MESSAGE_HEADER_LEN = 2;
/// 數(shù)據(jù)編碼
static List<int> encode(int type, var content) {
ByteData data = ByteData(MESSAGE_HEADER_LEN);
data.setUint16(0, type, Endian.little);
List<int> msg = data.buffer.asUint8List() + content.writeToBuffer().buffer.asUint8List();
return msg;
}
c.發(fā)消息
/// 發(fā)送
sendSocket(int type, var content) async {
IOWebSocketChannel channel = await SocketService.getInstance().getChannel();
if (channel == null) return;
List<int> msg = ProtobufUtil.encode(type, content);
channel.sink.add(msg);
}
sendSocket(11, message)
5.收消息、解碼
a.解碼
/// 數(shù)據(jù)解碼
static DecodedMsg decode(data) {
Int8List int8Data = Int8List.fromList(data);
Int8List contentTypeInt8Data = int8Data.sublist(0, MESSAGE_HEADER_LEN);
Int8List contentInt8Data = int8Data.sublist(MESSAGE_HEADER_LEN, int8Data.length);
int contentType = contentTypeInt8Data.elementAt(0);
GeneratedMessage content;
switch (contentType) {
case 10:
content = AckMessage.fromBuffer(contentInt8Data);
break;
case 11:
content = Message.fromBuffer(contentInt8Data);
break;
}
DecodedMsg decodedMsg;
if (contentType != null && content != null) {
decodedMsg = DecodedMsg(
contentType: contentType,
content: content,
);
}
return decodedMsg;
}
b.收消息
channel.stream.listen((data) {
DecodedMsg msg = ProtobufUtil.decode(data);
}
完結(jié),撒花??