如何在本地通过大于 1500 字节的 UDP 数据包发送浮点数并解析它们

How to send floats via UDP packets larger than 1500 bytes locally and parsing them

我正在尝试通过 UDP 发送大量浮点数。我正在使用浮点数,但不太确定如何将它们解析回服务器上的原始状态。服务器和客户端将在两个应用程序之间本地 运行。而服务器将转换为 C# 应用程序。

客户:

var PORT = 33333;
var HOST = '127.0.0.1';

var dgram = require('dgram');
_data =[-28.5686,97.3002,142.458,0.440512,2.45745,-0.144664,-0.17135,-18.0888,-0.507999,1.4921e-021,3.27051e-018,-0.0534133,-0.000146994,33.8001,0.463196,4.90246e-021,5.86576e-018,-0.0957984,2.09062,-14.5077,0.266143,-4.29059e-007,-1.04696e-007,-7.84019e-016,-4.04058,-15.1361,-3.75471,6.63063e-020,2.15707e-017,-0.352291,7.47538e-005,29.8537,5.90907,3.48822e-023,-4.28574e-019,0.00699938,1.40942,-15.474,0.186975,0.0293333,-0.019122,4.3858e-005,0.01778,-0.263464,0.123309,-0.196127,0.018499,0.0899181,-0.193886,0.0187146,0.0906704,-0.193708,0.0189286,0.0912595,-12.7908,0,-7.41445,-51.7233,9.71027,-4.09645,-0,1.34465,0,42.7628,43.1268,-53.5281,-0,0.542484,0,-15.8093,1.1398,-8.18984,-11.3353,5.42235,10.9137,-30.5178,-1.01592,1.72285,-26.2457,0,0,-0,0,0,-29.8264,-0.995051,0.607773,-112.753,0,0,-53.037,0,0,-0,0,0,-33.1392,-1.09366,5.26616,-111.292,0,0,-50.936,0,0,-0,0,0,-32.1005,-1.06312,0.623497,-103.333,0,0,-43.6037,0,0,-0,0,0,-5.9451,-0.207234,4.09042,-96.4444,0,0,-38.244,0,0,-0,0,0,19.4098,9.98358e-016,10.5068,50.3766,4.8873,2.22908,3.1563e-016,2.57567,-7.09555e-018,-36.3347,40.6501,48.4687,-7.43586e-006,0.592876,-2.70893e-006,16.9705,-0.244893,-1.64202,11.331,5.42212,-10.9131,29.2193,-0.97661,-1.74543,24.8369,0,0,0,0,-0,29.7912,-0.993986,-0.605762,112.622,0,0,52.9584,0,0,0,0,-0,33.0111,-1.08992,-3.26718,111.073,0,0,51.0729,0,0,0,0,-0,32.4514,-1.07348,1.33472,102.94,0,0,43.1189,0,0,0,0,-0,5.87599,-0.204834,-2.10028,96.0519,0,0,38.4021,0,0,0,0,-0,-2.97445,-2.05615,0.876116,5.61002,-7.05385,-0.893018];

var client = dgram.createSocket('udp4');
const buf = new Buffer(_data);

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

服务器:

var PORT = 33333;
var HOST = '127.0.0.1';

var dgram = require('dgram');
var server = dgram.createSocket('udp4');

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(message.length);

});

server.bind(PORT, HOST);

所以这是用 TypedArrays 将浮点数打包到 Buffer 的方法:

var ta = new Float32Array(_data);
var buffer = new Buffer(ta.buffer);

TypedArrays 是 Javascript 的新增内容,因此您的节点版本可能不支持它们。这是让他们进入 Buffer 的另一种方法:

var buffer = new Buffer(_data.length * 4);
_data.forEach(function(float, index){
    buffer.writeFloatLE(float, index*4);
});

现在您可以在服务器上阅读它们了。从 NodeJS 服务器,您可以像这样阅读它们:

server.on('message', function (message, remote) {
    console.log(message.length);
    var arr = [];
    for(var i = 0; i < message.length; i+=4){
        arr.push(message.readFloatLE(i));
    }
    //arr = your array of floats.
});

关于您关于 UDP 最大大小的问题,这将取决于您的网络的 MTU,当然还有您使用的数据类型。 Doubles 是 8 个字节,Floats 是 4 个字节,Strings 取决于您使用的编码。我用 Floats 对你的 _data 进行了测试,它得到了 864 个字节,Doubles 数据增长了两倍,使用字符串,它让我足够接近 Doubles(但数据取决于数字的长度)。

如果您不想发送超过允许的数量,我认为您只有两个选择。您可以分块发送或压缩它。

要压缩它,您可以使用 zlib 和结果 buffer:

var zlib = require('zlib');
zlib.deflate(buf, function(err, buf){ //deflate, gzip, etc
    client.send(buf, 0, buf.length, PORT, HOST, function(err, bytes) {
        if (err) throw err;
        console.log('UDP message sent to ' + HOST +':'+ PORT);
        client.close();
    });
});

然后在服务器上解压:

var zlib = require('zlib');
server.on('message', function (message, remote) {
    console.log(message.length);
    zlib.inflate(message, function(err, message){
        var arr = [];
        for(var i = 0; i < message.length; i+=4){
            arr.push(message.readFloatLE(i));
        }
        console.log(JSON.stringify(arr));
    });
});

FloatsDeflate/Inflate 使我减少了 1/4(大约 600 字节)。我会尝试其他 compression/decompression 方法,但请记住这里有性能价格。

如果您想分块发送,您可以估计有效载荷的大小。例如,如果您只想发送 500 个字节,那么您只能发送 (500 -28)/4 个元素 (118)。所以你拼接数组并先发送,然后再次拼接 118 个元素,直到剩下 0 个元素。

查看 Docs 其他数字类型(Int32、Floats、Doubles、BE、LE 等)的 Buffer 方法。