Vue项目使用goole-protobuf实现数据序列化和反序列化

本文介绍了如何使用protobuf编译器将.proto文件转换为js,以便在前端项目中使用。步骤包括下载工具、创建proto文件、编译并修改生成的js文件,以及实现发送和解包数据的功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

首先我们需要下载一个把.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);
}

封包后数据长这样

 将这数据再解包,

和封包前一模一样,成功啦!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值