0
点赞
收藏
分享

微信扫一扫

【小沐学前端】Node.js实现基于Protobuf协议的UDP通信(代码篇)

1、简介

1.1 node

Node.js 是一个开源的、跨平台的 JavaScript 运行时环境。

Node.js 是一个开源和跨平台的 JavaScript 运行时环境。 它是几乎任何类型项目的流行工具!

1.2 Protobuf

Protobuf 是一种用于 序列化 和 反序列化 对象的格式规范(rpc 通信协议)。

Protobuf 与 非结构化格式(如 JSON、XML)最大的区别在于,你必须为 protobufs 定义数据类型,最常用的方式是定义 .proto 文件。

2 代码示例

2.1 例子:hello.proto + udp

  • hello.proto
package yxy;
message helloworld
{
    message helloReq { required string name = 1; }
    message helloRsp
    {
        required int32 retcode = 1;
        optional string reply = 2;
    }
}

2.1.1 服务端:yxy_server.js

  • yxy_server.js
var ProtoBuf = require("protobufjs");
var dgram = require('dgram');
var PORT = 8080;
var HOST = '127.0.0.1';

var server = dgram.createSocket('udp4');
var root = ProtoBuf.loadSync("./hello.proto");
var HelloReq = root.lookupType("yxy.helloworld.helloReq");
var HelloRsp = root.lookupType("yxy.helloworld.helloRsp");

server.on('listening', function () {
    var address = server.address();
    console.log('UDP Server listening on ' + address.address + ":" + address.port);
});

server.on('message', function (message, remote) {
    console.log(remote.address + ':' + remote.port + ' - ' + message);
    console.log(HelloReq.decode(message) + ' from client!');

    var hCReq = HelloRsp.fromObject({retcode:200, reply:'Yeah!I\'m 杨小羊!'});
    var message = HelloRsp.encode(hCReq).finish();

    server.send(message, 0, message.length, remote.port, remote.address, function (err, bytes) {
        if (err) {
            throw err;
        }
        console.log('UDP message reply to ' + remote.address + ':' + remote.port);
    })
});

server.bind(PORT, HOST);

在这里插入图片描述

2.1.2 客户端:yxy_client.js

var dgram = require('dgram');
var ProtoBuf = require("protobufjs");
var PORT = 8080;
var HOST = '127.0.0.1';

var root = ProtoBuf.loadSync("./hello.proto");
var HelloReq = root.lookupType("yxy.helloworld.helloReq");
var HelloRsp = root.lookupType("yxy.helloworld.helloRsp");

var hCReq = HelloReq.fromObject({name:"杨小羊"});
var buffer = HelloReq.encode(hCReq).finish();
message = buffer; 

var socket = dgram.createSocket({
    type: 'udp4',
    fd: PORT
}, function (err, message) {
    if (err) {
        console.log(err);
    }
    console.log(message);
});

socket.send(message, 0, message.length, PORT, HOST, function (err, bytes) {
    if (err) {
        throw err;
    }
    console.log('UDP message sent to ' + HOST + ':' + PORT);
});

socket.on("message", function (msg, rinfo) {
    console.log("[Client] Received message: " + HelloRsp.decode(msg).reply + " from " + rinfo.address + ":" + rinfo.port);
    console.log(HelloRsp.decode(msg));
    socket.close();
});

socket.on('close', function () {
    console.log('socket closed.');
});

socket.on('error', function (err) {
    socket.close();
    console.log('socket err');
    console.log(err);
});

在这里插入图片描述

2.2 例子:user.proto + tcp

  • user.proto
syntax = "proto3";
package yxy;

message Login {
    required string name = 1;
    required string pwd = 2;
}
message Address{
  string province = 1;
  string city = 2;
  string country = 3;
}

2.2.1 服务端:yxy_tcpserver.js

  • yxy_tcpserver.js
const net = require("net");
const protobuf = require("protobufjs");
const PORT = 9090;
const HOST = '127.0.0.1';

protobuf.load("./user.proto", (err, root) => {
    if (err) throw err;
    const LoginMessage = root.lookupType("yxy.Login");
    const server = net.createServer((socket) => {
        console.log("New client connected");
        socket.on("data", (data) => {
            // 解码数据 
            const message = LoginMessage.decode(data);
            // 在这里处理消息
            console.log(message);
            // 编码响应 
            const responseData = LoginMessage.encode({
                name: "杨小羊",
                pwd: "123456"
            }).finish();
            // 将响应写回到连接 
            socket.write(responseData);
        });
        socket.on("close", () => {
            console.log("Client disconnected");
        });
    });
    server.listen(PORT, () => {
        console.log(`Server listening on localhost:${PORT}`);
    });
});

在这里插入图片描述

2.2.2 客户端:yxy_tcpclient.js

  • yxy_tcpclient.js
const net = require("net");
const protobuf = require("protobufjs");
const PORT = 9090;
const HOST = '127.0.0.1';

protobuf.load("./user.proto", (err, root) => {
    if (err) throw err;
    const LoginMessage = root.lookupType("yxy.Login");
    const client = net.createConnection({
        port: PORT
    }, () => {
        console.log("Connected to server");
        // 编码数据 
        const data = LoginMessage.encode({
            name: "爱看书的小沐",
            pwd: "666666"
        }).finish();
        // 将数据写到连接 
        client.write(data);
    });
    client.on("data", (data) => {
        // 解码服务器的响应 
        const message = LoginMessage.decode(data);
        // 在这里处理响应 
        console.log(message);
    });
    client.on("close", () => {
        console.log("Connection closed");
    });
});

在这里插入图片描述

结语

如果您觉得该方法或代码有一点点用处,可以给作者点个赞,或打赏杯咖啡;╮( ̄▽ ̄)╭ 如果您感觉方法或代码不咋地//(ㄒoㄒ)//,就在评论处留言,作者继续改进;o_O??? 如果您需要相关功能的代码定制化开发,可以留言私信作者;(✿◡‿◡) 感谢各位大佬童鞋们的支持!( ´ ▽´ )ノ ( ´ ▽´)っ!!!

举报

相关推荐

0 条评论