您的位置:首页 > 理论基础 > 计算机网络

参照protobuf,将json数据转换成二进制在网络中传输。

2014-08-01 14:25 701 查看
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));
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐