The background,
Recently, I was working on a requirement that needed to interact with the backend. For parallel development, I had the following dialogue with the backend:
Front-end: Can you give me a mock data?
Backend: Mock data is too much trouble, do it yourself!!
Front-end: How do I know what the data looks like and how to mock it? (poor)
Back end: Mock out the convention interface and throw me a proto file
Front end: What is Proto? How to mock data from Proto? Why use proto at the back end, JSON doesn’t smell good? In order to make up for his lack of a link, opens the path of Protobuf redemption.
What is a Protobuf?
Protobuf, as a cross-platform, language-independent and extensible method of serializing structured data, has been widely used in network data exchange and storage. It currently supports a variety of development languages (C++, Java, Python, Objective-C, C#, JavaNano, JavaScript, Ruby, Go, PHP). For details, please refer to github.com/52im/protob…
- advantages
(1) Small size after serialization, suitable for network transmission
(2) Support cross-platform, multi-language
(3) With good upgrade and compatibility (with backward compatibility, after updating the data structure, the old version can still be compatible)
(4) Faster serialization and deserialization
- disadvantages
Protobuf is a binary protocol, and the encoded data is not readable
Structure of Protobuf
Protobuf usage there are many uses, this time through an example to look at the basic use of Protobuf, specific use can be searched on the Internet related documents for learning.
syntax = "proto2"
package transferData;
message transferMessage {
required string name = 1;
required int32 age = 2;
enum SexEnum {
Boy = 0;
Girl = 1;
}
optional SexEnum SexEnum = 3;
}
Copy the code
- syntax = “proto2”;
This line is used to specify the syntax version, currently there are two versions proto2 and Proto3, the two versions are not compatible, if not specified, the default syntax is Proto2.
- package transferData;
The package name used to define the package;
- message
Message is the most basic unit of data in a Protobuf, where messages or members of other underlying data types can be nested;
- attribute
Each line in message is an attribute, such as Required String Name = 1, which looks like this:
mark | type | The property name | Attribute ordinal | [options] |
---|---|---|---|---|
required | string | name | = 1 | Some options |
(1) There are three types of labeling:
Required: Mandatory attribute;
Optional: Optional attributes;
Repeated: a repeated field, similar to a dynamic array;
Int32, int64, int, float, double, string, etc.
(3) Attribute name: the name used to represent the attribute;
(4) Sequence number of attributes: Protobuf For improving data compression and optionality and other functions defined, need to be defined in order, and no repetition is allowed;
(5) [options]: Protobuf provides some built-in options to choose from, which can greatly improve the scalability of Protobuf.
- enum
When defining a message type, you may need a field value to be one of the default values, where enumerated types come into play.
Note: there are many uses of protobuf, here only a brief introduction, there are like students can further their in-depth study.
Four, in actual combat
Protobuf.js package will be used for serialization and deserialization of proto files. Protobuf.js package will be used for serialization and deserialization of proto files. It is a pure JavaScript implementation that supports Node.js and browsers. It’s easy to use, extremely fast, and can be used with.Proto files right out of the box! (www.npmjs.com/package/pro…
4.1 Basic Usage
Proto file is protobuf.js package, commonly used methods mainly have the following:
- load()
Use this function to load the corresponding. Proto file. After loading, you can use the message inside and perform subsequent operations.
- lookupType()
After loading. Proto, initialize the used message, that is, complete the process of message instantiation.
- verify()
This function is used to verify that a common object is some corresponding message structure;
- encode()
Encode a Message instance or a generic JS object that can be used;
- decode()
Decode buffer to a Message instance. Failure to decode will rule out errors.
- create()
Creating a new message instance from a list of properties is superior to fromObject because it does not produce redundant transformations;
- fromObject()
Convert any invalid plain JS objects to Message instances;
- toObject()
Convert a Message instance to an arbitrary plain JS object.
There are other ways to use the library that you can learn by looking at its corresponding documentation. For the above transformation relationship, see the figure below (from the official document) :
4.2 the service side
It is the server. After receiving the message sent by the client, decode function in the ProtobufJS library is used to parse and obtain the result after parsing.
const net = require('net');
const protobuf = require('protobufjs');
const decodeData = data= > {
protobuf.load('./transfer.proto')
.then(root= > {
const transferMessage = root.lookupType('transferData.transferMessage');
const result = transferMessage.decode(data);
console.log(result); // transferMessage {name: 'roe roe ', age: 1, sexEnum: 1}
})
.catch(console.log);
}
const server = net.createServer(socket= > {
socket.on('data'.data= >{
decodeData(data);
});
socket.on('close'.() = > {
console.log('client disconnected!!! ');
});
});
server.on('error'.err= > {
throw new Error(err);
});
server.listen(8081.() = > {
console.log('server port is 8081');
});
Copy the code
4.3 the client
It is the client corresponding code, using the ProtobufJS library for corresponding operations, the serialized content sent to the server.
const net = require('net');
const protobuf = require('protobufjs');
const data = {
name: 'the roe deer roe deer'.age: 1.sexEnum: 1
};
let client = new net.Socket();
client.connect({
port: 8081
});
client.on('connect'.() = > {
setMessage(data);
});
client.on('data'.data= > {
console.log(data);
client.end();
});
function setMessage(data) {
protobuf.load('./transfer.proto')
.then(root= >{
// Instantiate message based on the contents of the proto file
const transferMessage = root.lookupType('transferData.transferMessage');
/ / verification
const errMsg = transferMessage.verify(data);
console.log('errMsg', errMsg);
if (errMsg) {
throw new Error(errMsg);
}
// Convert to message instance
const messageFromObj = transferMessage.fromObject(data);
console.log('messageFromObj', messageFromObj);
/ / code
const buffer = transferMessage.encode(messageFromObj).finish();
console.log(buffer);
/ / send
client.write(buffer);
})
.catch(console.log);
}
Copy the code
1. If you think this article is good, share and like it so that more people can see it
2. Welcome to pay attention to the front end line and surface of the public account, and open the front salvation road.