json数据格式在网络中传输需要的数据比二进制庞大太多,我们可以省去key,外加将数字不需要编码成字符串,直接二进制编码就OK。
pack : 将json压包,unpack解包成json。
var Struct = module.exports = {}; Struct.TYPE = { int8:1, int16:2, int32:3, uint8:4, uint16:5, uint32:7, string:8, object:9, aint8:10, aint16:11, aint32:12, auint8:13, auint16:14, auint32:15, aobject:16 }; // Struct.unpack = function(proto, buf) { var _unpack = function(proto, buf, pos) { var p = {}; var ret; var length; for (var k in proto) { var type = proto[k][0]; if (typeof type == 'object') { var json = type; type = 'object'; } if (proto[k].length == 2 && proto[k][1] == 'array') { type = 'a' + type; } var value = []; switch(Struct.TYPE[type]) { case Struct.TYPE.int8: p[k] = buf.readInt8(pos); pos += 1; break; case Struct.TYPE.int16: p[k] = buf.readInt16BE(pos); pos += 2; break; case Struct.TYPE.int32: p[k] = buf.readInt32BE(pos); pos += 4; break; case Struct.TYPE.uint8: p[k] = buf.readUInt8(pos); pos += 1; break; case Struct.TYPE.uint16: p[k] = buf.readUInt16BE(pos); pos += 2; break; case Struct.TYPE.uint32: p[k] = buf.readUInt32BE(pos); pos += 4; break; case Struct.TYPE.string: ret = getLen(buf,pos); pos = ret[1]; p[k] = buf.toString('utf-8',pos, pos + ret[0]); pos += ret[0]; break; case Struct.TYPE.object: ret = _unpack(json, buf, pos); p[k] = ret[0]; pos = ret[1]; break; case Struct.TYPE.aint8: ret = getLen(buf,pos); length = ret[0]; pos = ret[1]; for (var i=0; i < length; i++) { value.push(buf.readInt8(pos)); pos += 1; } p[k] = value; break; case Struct.TYPE.aint16: ret = getLen(buf,pos); length = ret[0]; pos = ret[1]; for (var i=0; i < length; i++) { value.push(buf.readInt16BE(pos)); pos += 2; } p[k] = value; break; case Struct.TYPE.aint32: ret = getLen(buf,pos); length = ret[0]; pos = ret[1]; for (var i=0; i < length; i++) { value.push(buf.readInt32BE(pos)); pos += 4; } p[k] = value; break; case Struct.TYPE.auint8: ret = getLen(buf,pos); length = ret[0]; pos = ret[1]; for (var i=0; i < length; i++) { value.push(buf.readUInt8(pos)); pos += 1; } p[k] = value; break; case Struct.TYPE.auint16: ret = getLen(buf,pos); length = ret[0]; pos = ret[1]; for (var i=0; i < length; i++) { value.push(buf.readUInt16BE(pos)); pos += 2; } p[k] = value; break; case Struct.TYPE.auint32: ret = getLen(buf,pos); length = ret[0]; pos = ret[1]; for (var i=0; i < length; i++) { value.push(buf.readUInt32BE(pos)); pos += 4; } p[k] = value; break; case Struct.TYPE.astring: ret = getLen(buf,pos); length = ret[0]; pos = ret[1]; for (var i=0; i < length; i++) { ret = getLen(buf,pos); pos = ret[1]; value.push(buf.toString('utf-8',pos, pos + ret[0])); pos += ret[0]; } p[k] = value; break; case Struct.TYPE.aobject: ret = getLen(buf,pos); length = ret[0]; pos = ret[1]; for (var i=0; i < length; i++) { ret = _unpack(json, buf, pos); pos = ret[1]; value.push(ret[0]); } p[k] = value; break; } } return [p,pos]; } return _unpack(proto, buf, 0)[0]; } Struct.pack = function(proto, msg) { function _pack(proto, msg, buf, pos) { for (var k in proto) { var type = proto[k][0]; if (typeof type == 'object') { var json = type; type = 'object'; } if (proto[k].length == 2 && proto[k][1] == 'array') { type = 'a' + type; } switch(Struct.TYPE[type]) { case Struct.TYPE.int8: buf.writeInt8(msg[k], pos); pos += 1; break; case Struct.TYPE.int16: buf.writeInt16BE(msg[k], pos); pos += 2; break; case Struct.TYPE.int32: buf.writeInt32BE(msg[k],pos); pos += 4; break; case Struct.TYPE.uint8: buf.writeUInt8(msg[k], pos); pos += 1; break; case Struct.TYPE.uint16: buf.writeUInt16BE(msg[k],pos); pos += 2; break; case Struct.TYPE.uint32: buf.writeUInt32BE(msg[k], pos); pos += 4; break; case Struct.TYPE.string: pos = setLen(buf, msg[k].length, pos); buf.write(msg[k],pos); pos += msg[k].length; break; case Struct.TYPE.object: pos = _pack(json, msg[k], buf, pos); break; case Struct.TYPE.aint8: var list = msg[k]; pos = setLen(buf, list.length, pos); for (var i=0; i < list.length; i++) { buf.writeInt8(list[i], pos++); } break; case Struct.TYPE.aint16: var list = msg[k]; pos = setLen(buf, list.length, pos); for (var i=0; i < list.length; i++) { buf.writeInt16BE(list[i], pos); pos += 2; } break; case Struct.TYPE.aint32: var list = msg[k]; pos = setLen(buf, list.length, pos); for (var i=0; i < list.length; i++) { buf.writeInt32BE(list[i], pos); pos += 4; } break; case Struct.TYPE.auint8: var list = msg[k]; pos = setLen(buf, list.length, pos); for (var i=0; i < list.length; i++) { buf.writeUInt8(list[i], pos++); } break; case Struct.TYPE.auint16: var list = msg[k]; pos = setLen(buf, list.length, pos); for (var i=0; i < list.length; i++) { buf.writeUInt16BE(list[i], pos); pos += 2; } break; case Struct.TYPE.auint32: var list = msg[k]; pos = setLen(buf, list.length, pos); for (var i=0; i < list.length; i++) { buf.writeUInt32BE(list[i], pos); pos +=4; } break; case Struct.TYPE.astring: var list = msg[k]; pos = setLen(buf, list.length, pos); for (var i=0; i < list.length; i++) { pos = setLen(buf, list[i].length,pos); buf.write(list[i],pos); pos += list[i].length; } break; case Struct.TYPE.aobject: var list = msg[k]; pos = setLen(buf, list.length, pos); for (var i=0; i < list.length; i++) { pos = _pack(json, list[i], buf, pos); } break; } //console.log('key: ' + k); //console.log('pos: ' + pos); } return pos; } var length = jsonSize(proto, msg); var buf = new Buffer(length); _pack(proto, msg, buf, 0); return buf; }; var jsonSize = function(proto, msg) { function _size(proto, msg) { var size = 0; var buf = new Buffer(4); for (var k in proto) { var type = proto[k][0]; if (typeof type == 'object') { var json = type; type = 'object'; } if (proto[k].length == 2 && proto[k][1] == 'array') { type = 'a' + type; } switch(Struct.TYPE[type]) { case Struct.TYPE.int8: size += 1; break; case Struct.TYPE.int16: size += 2; break; case Struct.TYPE.int32: size += 4; break; case Struct.TYPE.uint8: size += 1; break; case Struct.TYPE.uint16: size += 2; break; case Struct.TYPE.uint32: size += 4; break; case Struct.TYPE.string: size += setLen(buf, msg[k].length, 0); size += msg[k].length; break; case Struct.TYPE.object: size += _size(json, msg[k]); break; case Struct.TYPE.aint8: var list = msg[k]; size += setLen(buf, list.length, 0); size += list.length; break; case Struct.TYPE.aint16: var list = msg[k]; size += setLen(buf, list.length, 0); size += list.length * 2; break; case Struct.TYPE.aint32: var list = msg[k]; size += setLen(buf, list.length, 0); size += list.length * 4; break; case Struct.TYPE.auint8: var list = msg[k]; size += setLen(buf, list.length, 0); size += list.length; break; case Struct.TYPE.auint16: var list = msg[k]; size += setLen(buf, list.length, 0); size += list.length * 2; break; case Struct.TYPE.auint32: var list = msg[k]; size += setLen(buf, list.length, 0); size += list.length * 4; break; case Struct.TYPE.astring: var list = msg[k]; size += setLen(buf, list.length, 0); for (var i=0; i < list.length; i++) { size += setLen(buf, list[i].length,0); size += list[i].length; } break; case Struct.TYPE.aobject: var list = msg[k]; size += setLen(buf, list.length, 0); for (var i=0; i < list.length; i++) { size += _size(json, list[i]); } break; } } return size; } var size = 0; size += _size(proto, msg); return size; } var MASK_7 = (1<<7) - 1; var MASK_8 = (1<<8) - 1; var MAX_LEN = (1<<28); //不定长记录长度,1-4个字节,和MQTT表示长度的方法相同 var getLen = function(buf, pos) { var len = 0; for (var i = 0; i < 4; i++) { var value = buf.readUInt8(pos); //console.log('get: ' + value); len += (value & MASK_7) << (7 * i); pos += 1; if (value < 127) { break; } } return [len, pos]; } var setLen = function(buf, len, pos) { while(len > 0) { var value = len & MASK_8; len = len >> 7; if (len > 0) { value = value | 128; } buf.writeUInt8(value, pos++); } return pos; }
测试代码:
var Struct = require('./struct'); var proto = { int8 : ['int8'], int16 : ['int16'], int32 : ['int32'], uint8 : ['uint8'], uint16 : ['uint16'], uint32 : ['uint32'], string : ['string'], aint8 : ['int8', 'array'], aint16 : ['int16', 'array'], aint32 : ['int32', 'array'], auint8 : ['uint8', 'array'], auint16: ['uint16', 'array'], auint32: ['uint32', 'array'], object : [ {int8: ['int8'], int16: ['int16'], string: ['string'], astring: ['astring']} ], aobject : [ {int8: ['int8'], int16: ['int16'], string: ['string'], astring: ['astring']}, 'array' ], astring: ['string', 'array'] } var msg = { int8 : 12, int16 : 1234, int32 : 12345, uint8 : 130,// > 128 uint16 : 32800, // >> 128 * 256 uint32 : 3221245472, // >> 3 * (1<<30) string : 'hello world', aint8 : [-1, -2, -3, -5, -6], aint16 : [-11, -12, -13, -15, -17], aint32 : [-337, -338, -339, -3310, -3311], auint8 : [1, 2, 3, 4], auint16: [8, 9, 10, 11, 12], auint32: [12, 13, 15, 16], object : {int8: 12, int16: 1234, string: 'somebady', astring: ['save me', 'Dont stop me now']}, aobject : [{int8: 12, int16: 1234, string: 'somebady', astring: ['save me', 'Dont stop me now']}, {int8: 12, int16: 1234, string: 'somebady', astring: ['save me', 'Dont stop me now']}], astring: ['melo', 'kaka', 'much', 'save'] } var buf = Struct.pack(proto, msg); console.log(buf); var remsg = Struct.unpack(proto, buf); console.log(JSON.stringify(remsg));
参照protobuf,将json数据转换成二进制在网络中传输。
时间: 2024-10-13 12:30:02