閱讀時可能需要你事先對flutter,protobuf有基本了解,flutter的基本操作可以在flutter中文網(wǎng)中找到
在flutter中protobuf的導(dǎo)入
- 在pubspec中添加 然后更新
dependencies:
flutter:
sdk: flutter
// 引入protobuf
protobuf: ^0.13.4
- 使用pb的dart插件生成你的模型文件
過程簡單請百度一下
flutter中socket的基本使用
- 引入頭文件 創(chuàng)建地址和端口
import 'dart:io';
//地址
const String adress = '你的服務(wù)器地址';
//端口
const int port = 你的服務(wù)器端口;
- 設(shè)置一個管理類
class Client {
//socket實(shí)例
Socket _socket;
//數(shù)據(jù)接收組
var _recList;
//單例方法
factory Client() =>_getInstance();
static Client get instance => _getInstance();
static Client _instance;
Client._internal() {
// 初始化
}
static Client _getInstance() {
if (_instance == null) {
_instance = new Client._internal();
}
return _instance;
}
}
- 初始化socket實(shí)例傳輸并設(shè)置接受數(shù)據(jù)回調(diào)
Future<Null> startClient() async {
//初始化接收組
_recList = new List<int>();
//建立鏈接
_socket=await Socket.connect(adress, port);
//添加數(shù)據(jù)監(jiān)聽
_socket.transform(base64.encoder).listen((data){
//接受數(shù)據(jù)并處理
List dataList = base64Decode(data);
//接收后處理 詳情可見下文
readData(dataList);
});
}
在protobuf中,與服務(wù)器交換的數(shù)據(jù)是模型,而在dart中data類型用List類型表示,因此在本例中使用base64對收回數(shù)據(jù)進(jìn)行編碼后解碼為List以供pb解析
- 發(fā)送數(shù)據(jù)
void sendMsg(List msg){
_socket.add(msg);
}
flutter中protobuf的基本使用
構(gòu)建消息體
- 引入pb文件以及數(shù)據(jù)處理文件
import 'package:prgramFile/all.pbserver.dart';
import 'package:fixnum/fixnum.dart';
本例中因使用int64類型數(shù)據(jù)因此需引入 fixnum: ^0.10.9
- 創(chuàng)建一個消息
const int CLIENT_TAG_BEGIN = 10000;
//心跳包
Msg heartBeatrMsg(){
HeartbeatReq req = HeartbeatReq.create();
req.count = CLIENT_TAG_BEGIN;
Head head = new Head();
head.msgid = MsgID.heart_beat_id;
Msg msg =new Msg();
msg.head = head;
msg.heartbeatQ = req;
return msg;
}
關(guān)于pb消息構(gòu)建的內(nèi)容可以百度相關(guān)教程
消息的編碼和解碼
使用 Msg.fromBuffer() 方法從二進(jìn)制數(shù)據(jù)獲取模型而昨。
該方法為類方法
使用 msg.writeToBuffer()方法將實(shí)例轉(zhuǎn)換為二進(jìn)制數(shù)據(jù)
該方法為實(shí)例方法
使用Socket與服務(wù)器進(jìn)行pb協(xié)議數(shù)據(jù)傳輸?shù)膶?shí)例
本例中服務(wù)器對數(shù)據(jù)協(xié)議的規(guī)則為消息的前8位是描述一個模型數(shù)據(jù)長度的字符串,不足8位的補(bǔ)"0",根據(jù)后臺對數(shù)據(jù)規(guī)則定義不同因此僅供數(shù)據(jù)處理參考
- 對發(fā)出的消息添加描述長度的索引頭
由于實(shí)際服務(wù)器獲取的是消息的前8個字節(jié)數(shù)據(jù)按照字符串處理,對應(yīng)的純data類型為 Uint8List(8)
將每一位按照ascII表數(shù)字對應(yīng)即可
//添加索引頭
List appendHeaderWithMsg(Msg bodyMsg){
//獲取消息長度
String bodyLength = bodyMsg.writeToBuffer().length.toString();
//補(bǔ)0位數(shù)
int supplementCount = 8 - bodyMsg.writeToBuffer().length.toString().length;
//新索引頭
Uint8List headerList = Uint8List(8);
//填入索引信息
for(int i = 0;i < supplementCount; i++){
//補(bǔ)0
headerList[i] = 48;
}
for(int i = supplementCount;i < 8; i++){
//有效信息
headerList[i] = 48 + num.tryParse(bodyLength.substring(i - supplementCount,i - supplementCount + 1));
}
//序列化
List resultList = headerList + bodyMsg.writeToBuffer();
return resultList;
}
- 發(fā)送消息
- 接收以及處理
void readData(List dataList){
//接收并暫存
_recList = _recList + dataList;
//當(dāng)接收到的數(shù)據(jù)長度大于8讀取消息頭
while(_recList.length > 8 ){
int headerLength = 8;
//讀取消息體長度
int msgLength = int.parse(utf8.decode(_recList.sublist(0,8)));
int sourceLength = _recList.length;
//當(dāng)收到的消息超過消息頭描述的消息體長度時取出消息體并解碼
if(_recList.length >= headerLength + msgLength){
Msg msg = Msg.fromBuffer(_recList.sublist(headerLength,headerLength + msgLength));
//讀取后刪除已讀取的消息
_recList = _recList.sublist(headerLength + msgLength,sourceLength);
}
}