首先我们需要下载一个把.proto文件编译成js文件的编译工具。下载地址:https://github.com/protocolbuffers/protobuf/releases?page=4
选择3.20或以前的版本下载。解压后把里面的.exe文件复制到我们的vue项目中,路径如下:
需要创建一个proto文件来定义数据类型,格式如下:
syntax = "proto3";
package myPackage;
message LineInfo{
string key = 1;
int32 Db = 2;
}
proto文件与.exe文件平级,下一步使用编译器将.proto文件编译成js文件,前端才能使用
在cmd中执行
.\protoc --js_out=import_style=commonjs,binary:. test.proto
这句执行后会生成一个test_pb.js文件,打开该文件,里面有两行代码需要修改
var jspb = require('google-protobuf');//前
import * as jspb from 'google-protobuf';//后
goog.object.extend(exports, proto.myPackage);//前
export default proto.myPackage;//后
新建一个js文件
import * as Proto from '/@/assets/test_pb.js';
//消息类型定义
const NETWORK_MESSAGE_ID = {
MACHINE_DATA: 1,
LINE_INFO_REQUEST: 2,
};
//传入消息类型、消息内容。返回封包后的数据
//sendPacket(NETWORK_MESSAGE_ID.LINE_INFO_REQUEST, { key: '1234567333', Db: 1 });
const sendPacket = (networkMessageId: any, packet: any) => {
try {
var HEAD_SIZE = 4;
var TYPE_SIZE = 4;
let a = new Proto.default.LineInfo();
a.setKey(packet.key);
a.setDb(packet.Db);
let streamForProto = a.serializeBinary(); //序列化
var bufferSize = HEAD_SIZE + TYPE_SIZE + streamForProto.length; //算数据包的长度,包括头部大小(HEAD SIZE)、类型大小(TYPE SIZE)和数据长度。
const sendBuffer = new Uint8Array(bufferSize); // 创建一个长度为bufferSize的空白字节数组
var bufferSizeBytes = getBytes(bufferSize);
var networkMessageBytes = getBytes(networkMessageId);
sendBuffer.set(bufferSizeBytes, HEAD_SIZE * 0); //header
sendBuffer.set(networkMessageBytes, HEAD_SIZE); //type
sendBuffer.set(streamForProto, HEAD_SIZE + TYPE_SIZE); //body
//SplitReceivePacket(sendBuffer); //将封包数据解包
} catch (ex: any) {
console.log('send Error: ' + ex.message);
}
return sendBuffer
}
//解包数据
const SplitReceivePacket = (receiveBuffer: any) => {
var HEAD_SIZE = 4;
var TYPE_SIZE = 4;
var bytesRead = receiveBuffer.length;
var position = 0;
while (position < bytesRead) {
var bytesBuffer = new Uint8Array(HEAD_SIZE);
bytesBuffer.set(receiveBuffer.slice(position + 0, position + 0 + HEAD_SIZE), HEAD_SIZE * 0); //header
var bufferSize = GetInt(bytesBuffer);
var messageIdBuffer = new Uint8Array(TYPE_SIZE);
messageIdBuffer.set(receiveBuffer.slice(position + HEAD_SIZE, position + HEAD_SIZE + TYPE_SIZE), TYPE_SIZE * 0); //type
var networkMessage = GetInt(messageIdBuffer);
if (position + bufferSize > bytesRead) {
console.log('Error receive packet,packet is too long: ' + bufferSize);
break;
}
var rspPacket = UnPack(networkMessage, position + HEAD_SIZE + TYPE_SIZE, bufferSize - HEAD_SIZE - TYPE_SIZE, receiveBuffer);
if (rspPacket != null) {
console.log(rspPacket, '解包后');
}
position += bufferSize;
}
};
const UnPack = (networkMessage: number, startIndex: number, length: number, buffer: any) => {
var packet = null;
try {
var streamForProto = buffer.slice(startIndex, startIndex + length);//body
switch (networkMessage) {
case 1:
packet = Proto.default.LineInfo.deserializeBinary(streamForProto);
break;
case 2:
packet = Proto.default.LineInfo.deserializeBinary(streamForProto);
break;
default:
console.log('No Such Packet, packet type is ' + networkMessage);
break;
}
} catch (ex: any) {
console.log(ex.Message + '\n ' + ex.StackTrace + '\n' + ex.Source);
}
return packet?.toObject();
};
//整数转字节数组
function getBytes(value: any) {
var b = new Uint8Array(4);
b[0] = value;
b[1] = value >> 8;
b[2] = value >> 16;
b[3] = value >> 24;
return b;
}
//字节数组转整数
function GetInt(b: any) {
return b[0] | (b[1] << 8) | (b[2] << 16) | (b[3] << 24);
}
封包后数据长这样
将这数据再解包,
和封包前一模一样,成功啦!