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

时间:2024-11-01 15:33:50

http://blog.****.net/gamesofsailing/article/details/38335753?utm_source=tuicool&utm_medium=referral

json数据格式在网络中传输需要的数据比二进制庞大太多,我们可以省去key,外加将数字不需要编码成字符串,直接二进制编码就OK。

pack : 将json压包,unpack解包成json。

  1. var Struct = module.exports = {};
  2. Struct.TYPE = {
  3. int8:1,
  4. int16:2,
  5. int32:3,
  6. uint8:4,
  7. uint16:5,
  8. uint32:7,
  9. string:8,
  10. object:9,
  11. aint8:10,
  12. aint16:11,
  13. aint32:12,
  14. auint8:13,
  15. auint16:14,
  16. auint32:15,
  17. aobject:16
  18. };
  19. //
  20. Struct.unpack = function(proto, buf) {
  21. var _unpack = function(proto, buf, pos) {
  22. var p = {};
  23. var ret;
  24. var length;
  25. for (var k in proto) {
  26. var type = proto[k][0];
  27. if (typeof type == 'object') {
  28. var json = type;
  29. type = 'object';
  30. }
  31. if (proto[k].length == 2 && proto[k][1] == 'array') {
  32. type = 'a' + type;
  33. }
  34. var value = [];
  35. switch(Struct.TYPE[type]) {
  36. case Struct.TYPE.int8:
  37. p[k] = buf.readInt8(pos);
  38. pos += 1;
  39. break;
  40. case Struct.TYPE.int16:
  41. p[k] = buf.readInt16BE(pos);
  42. pos += 2;
  43. break;
  44. case Struct.TYPE.int32:
  45. p[k] = buf.readInt32BE(pos);
  46. pos += 4;
  47. break;
  48. case Struct.TYPE.uint8:
  49. p[k] = buf.readUInt8(pos);
  50. pos += 1;
  51. break;
  52. case Struct.TYPE.uint16:
  53. p[k] = buf.readUInt16BE(pos);
  54. pos += 2;
  55. break;
  56. case Struct.TYPE.uint32:
  57. p[k] = buf.readUInt32BE(pos);
  58. pos += 4;
  59. break;
  60. case Struct.TYPE.string:
  61. ret = getLen(buf,pos);
  62. pos = ret[1];
  63. p[k] = buf.toString('utf-8',pos, pos + ret[0]);
  64. pos += ret[0];
  65. break;
  66. case Struct.TYPE.object:
  67. ret = _unpack(json, buf, pos);
  68. p[k] = ret[0];
  69. pos = ret[1];
  70. break;
  71. case Struct.TYPE.aint8:
  72. ret = getLen(buf,pos);
  73. length = ret[0];
  74. pos = ret[1];
  75. for (var i=0; i < length; i++) {
  76. value.push(buf.readInt8(pos));
  77. pos += 1;
  78. }
  79. p[k] = value;
  80. break;
  81. case Struct.TYPE.aint16:
  82. ret = getLen(buf,pos);
  83. length = ret[0];
  84. pos = ret[1];
  85. for (var i=0; i < length; i++) {
  86. value.push(buf.readInt16BE(pos));
  87. pos += 2;
  88. }
  89. p[k] = value;
  90. break;
  91. case Struct.TYPE.aint32:
  92. ret = getLen(buf,pos);
  93. length = ret[0];
  94. pos = ret[1];
  95. for (var i=0; i < length; i++) {
  96. value.push(buf.readInt32BE(pos));
  97. pos += 4;
  98. }
  99. p[k] = value;
  100. break;
  101. case Struct.TYPE.auint8:
  102. ret = getLen(buf,pos);
  103. length = ret[0];
  104. pos = ret[1];
  105. for (var i=0; i < length; i++) {
  106. value.push(buf.readUInt8(pos));
  107. pos += 1;
  108. }
  109. p[k] = value;
  110. break;
  111. case Struct.TYPE.auint16:
  112. ret = getLen(buf,pos);
  113. length = ret[0];
  114. pos = ret[1];
  115. for (var i=0; i < length; i++) {
  116. value.push(buf.readUInt16BE(pos));
  117. pos += 2;
  118. }
  119. p[k] = value;
  120. break;
  121. case Struct.TYPE.auint32:
  122. ret = getLen(buf,pos);
  123. length = ret[0];
  124. pos = ret[1];
  125. for (var i=0; i < length; i++) {
  126. value.push(buf.readUInt32BE(pos));
  127. pos += 4;
  128. }
  129. p[k] = value;
  130. break;
  131. case Struct.TYPE.astring:
  132. ret = getLen(buf,pos);
  133. length = ret[0];
  134. pos = ret[1];
  135. for (var i=0; i < length; i++) {
  136. ret = getLen(buf,pos);
  137. pos = ret[1];
  138. value.push(buf.toString('utf-8',pos, pos + ret[0]));
  139. pos += ret[0];
  140. }
  141. p[k] = value;
  142. break;
  143. case Struct.TYPE.aobject:
  144. ret = getLen(buf,pos);
  145. length = ret[0];
  146. pos = ret[1];
  147. for (var i=0; i < length; i++) {
  148. ret = _unpack(json, buf, pos);
  149. pos = ret[1];
  150. value.push(ret[0]);
  151. }
  152. p[k] = value;
  153. break;
  154. }
  155. }
  156. return [p,pos];
  157. }
  158. return _unpack(proto, buf, 0)[0];
  159. }
  160. Struct.pack = function(proto, msg) {
  161. function _pack(proto, msg, buf, pos) {
  162. for (var k in proto) {
  163. var type = proto[k][0];
  164. if (typeof type == 'object') {
  165. var json = type;
  166. type = 'object';
  167. }
  168. if (proto[k].length == 2 && proto[k][1] == 'array') {
  169. type = 'a' + type;
  170. }
  171. switch(Struct.TYPE[type]) {
  172. case Struct.TYPE.int8:
  173. buf.writeInt8(msg[k], pos);
  174. pos += 1;
  175. break;
  176. case Struct.TYPE.int16:
  177. buf.writeInt16BE(msg[k], pos);
  178. pos += 2;
  179. break;
  180. case Struct.TYPE.int32:
  181. buf.writeInt32BE(msg[k],pos);
  182. pos += 4;
  183. break;
  184. case Struct.TYPE.uint8:
  185. buf.writeUInt8(msg[k], pos);
  186. pos += 1;
  187. break;
  188. case Struct.TYPE.uint16:
  189. buf.writeUInt16BE(msg[k],pos);
  190. pos += 2;
  191. break;
  192. case Struct.TYPE.uint32:
  193. buf.writeUInt32BE(msg[k], pos);
  194. pos += 4;
  195. break;
  196. case Struct.TYPE.string:
  197. pos = setLen(buf, msg[k].length, pos);
  198. buf.write(msg[k],pos);
  199. pos += msg[k].length;
  200. break;
  201. case Struct.TYPE.object:
  202. pos = _pack(json, msg[k], buf, pos);
  203. break;
  204. case Struct.TYPE.aint8:
  205. var list = msg[k];
  206. pos = setLen(buf, list.length, pos);
  207. for (var i=0; i < list.length; i++) {
  208. buf.writeInt8(list[i], pos++);
  209. }
  210. break;
  211. case Struct.TYPE.aint16:
  212. var list = msg[k];
  213. pos = setLen(buf, list.length, pos);
  214. for (var i=0; i < list.length; i++) {
  215. buf.writeInt16BE(list[i], pos);
  216. pos += 2;
  217. }
  218. break;
  219. case Struct.TYPE.aint32:
  220. var list = msg[k];
  221. pos = setLen(buf, list.length, pos);
  222. for (var i=0; i < list.length; i++) {
  223. buf.writeInt32BE(list[i], pos);
  224. pos += 4;
  225. }
  226. break;
  227. case Struct.TYPE.auint8:
  228. var list = msg[k];
  229. pos = setLen(buf, list.length, pos);
  230. for (var i=0; i < list.length; i++) {
  231. buf.writeUInt8(list[i], pos++);
  232. }
  233. break;
  234. case Struct.TYPE.auint16:
  235. var list = msg[k];
  236. pos = setLen(buf, list.length, pos);
  237. for (var i=0; i < list.length; i++) {
  238. buf.writeUInt16BE(list[i], pos);
  239. pos += 2;
  240. }
  241. break;
  242. case Struct.TYPE.auint32:
  243. var list = msg[k];
  244. pos = setLen(buf, list.length, pos);
  245. for (var i=0; i < list.length; i++) {
  246. buf.writeUInt32BE(list[i], pos);
  247. pos +=4;
  248. }
  249. break;
  250. case Struct.TYPE.astring:
  251. var list = msg[k];
  252. pos = setLen(buf, list.length, pos);
  253. for (var i=0; i < list.length; i++) {
  254. pos = setLen(buf, list[i].length,pos);
  255. buf.write(list[i],pos);
  256. pos += list[i].length;
  257. }
  258. break;
  259. case Struct.TYPE.aobject:
  260. var list = msg[k];
  261. pos = setLen(buf, list.length, pos);
  262. for (var i=0; i < list.length; i++) {
  263. pos = _pack(json, list[i], buf, pos);
  264. }
  265. break;
  266. }
  267. //console.log('key: ' + k);
  268. //console.log('pos: ' + pos);
  269. }
  270. return pos;
  271. }
  272. var length = jsonSize(proto, msg);
  273. var buf = new Buffer(length);
  274. _pack(proto, msg, buf, 0);
  275. return buf;
  276. };
  277. var jsonSize = function(proto, msg) {
  278. function _size(proto, msg) {
  279. var size = 0;
  280. var buf = new Buffer(4);
  281. for (var k in proto) {
  282. var type = proto[k][0];
  283. if (typeof type == 'object') {
  284. var json = type;
  285. type = 'object';
  286. }
  287. if (proto[k].length == 2 && proto[k][1] == 'array') {
  288. type = 'a' + type;
  289. }
  290. switch(Struct.TYPE[type]) {
  291. case Struct.TYPE.int8:
  292. size += 1;
  293. break;
  294. case Struct.TYPE.int16:
  295. size += 2;
  296. break;
  297. case Struct.TYPE.int32:
  298. size += 4;
  299. break;
  300. case Struct.TYPE.uint8:
  301. size += 1;
  302. break;
  303. case Struct.TYPE.uint16:
  304. size += 2;
  305. break;
  306. case Struct.TYPE.uint32:
  307. size += 4;
  308. break;
  309. case Struct.TYPE.string:
  310. size += setLen(buf, msg[k].length, 0);
  311. size += msg[k].length;
  312. break;
  313. case Struct.TYPE.object:
  314. size += _size(json, msg[k]);
  315. break;
  316. case Struct.TYPE.aint8:
  317. var list = msg[k];
  318. size += setLen(buf, list.length, 0);
  319. size += list.length;
  320. break;
  321. case Struct.TYPE.aint16:
  322. var list = msg[k];
  323. size += setLen(buf, list.length, 0);
  324. size += list.length * 2;
  325. break;
  326. case Struct.TYPE.aint32:
  327. var list = msg[k];
  328. size += setLen(buf, list.length, 0);
  329. size += list.length * 4;
  330. break;
  331. case Struct.TYPE.auint8:
  332. var list = msg[k];
  333. size += setLen(buf, list.length, 0);
  334. size += list.length;
  335. break;
  336. case Struct.TYPE.auint16:
  337. var list = msg[k];
  338. size += setLen(buf, list.length, 0);
  339. size += list.length * 2;
  340. break;
  341. case Struct.TYPE.auint32:
  342. var list = msg[k];
  343. size += setLen(buf, list.length, 0);
  344. size += list.length * 4;
  345. break;
  346. case Struct.TYPE.astring:
  347. var list = msg[k];
  348. size += setLen(buf, list.length, 0);
  349. for (var i=0; i < list.length; i++) {
  350. size += setLen(buf, list[i].length,0);
  351. size += list[i].length;
  352. }
  353. break;
  354. case Struct.TYPE.aobject:
  355. var list = msg[k];
  356. size += setLen(buf, list.length, 0);
  357. for (var i=0; i < list.length; i++) {
  358. size += _size(json, list[i]);
  359. }
  360. break;
  361. }
  362. }
  363. return size;
  364. }
  365. var size = 0;
  366. size += _size(proto, msg);
  367. return size;
  368. }
  369. var MASK_7 = (1<<7) - 1;
  370. var MASK_8 = (1<<8) - 1;
  371. var MAX_LEN = (1<<28);
  372. //不定长记录长度,1-4个字节,和MQTT表示长度的方法相同
  373. var getLen = function(buf, pos) {
  374. var len = 0;
  375. for (var i = 0; i < 4; i++) {
  376. var value = buf.readUInt8(pos);
  377. //console.log('get: ' + value);
  378. len += (value & MASK_7) << (7 * i);
  379. pos += 1;
  380. if (value < 127) {
  381. break;
  382. }
  383. }
  384. return [len, pos];
  385. }
  386. var setLen = function(buf, len, pos) {
  387. while(len > 0) {
  388. var value = len & MASK_8;
  389. len = len >> 7;
  390. if (len > 0) {
  391. value = value | 128;
  392. }
  393. buf.writeUInt8(value, pos++);
  394. }
  395. return pos;
  396. }

测试代码:

  1. var Struct = require('./struct');
  2. var proto = {
  3. int8   : ['int8'],
  4. int16  : ['int16'],
  5. int32  : ['int32'],
  6. uint8  : ['uint8'],
  7. uint16 : ['uint16'],
  8. uint32 : ['uint32'],
  9. string : ['string'],
  10. aint8  : ['int8', 'array'],
  11. aint16 : ['int16', 'array'],
  12. aint32 : ['int32', 'array'],
  13. auint8 : ['uint8', 'array'],
  14. auint16: ['uint16', 'array'],
  15. auint32: ['uint32', 'array'],
  16. object : [
  17. {int8: ['int8'], int16: ['int16'], string: ['string'], astring: ['astring']}
  18. ],
  19. aobject : [
  20. {int8: ['int8'], int16: ['int16'], string: ['string'], astring: ['astring']},
  21. 'array'
  22. ],
  23. astring: ['string', 'array']
  24. }
  25. var msg = {
  26. int8   : 12,
  27. int16  : 1234,
  28. int32  : 12345,
  29. uint8  : 130,// > 128
  30. uint16 : 32800, // >> 128 * 256
  31. uint32 : 3221245472, // >> 3 * (1<<30)
  32. string : 'hello world',
  33. aint8  : [-1, -2, -3, -5, -6],
  34. aint16 : [-11, -12, -13, -15, -17],
  35. aint32 : [-337, -338, -339, -3310, -3311],
  36. auint8 : [1, 2, 3, 4],
  37. auint16: [8, 9, 10, 11, 12],
  38. auint32: [12, 13, 15, 16],
  39. object : {int8: 12, int16: 1234, string: 'somebady', astring: ['save me', 'Dont stop me now']},
  40. 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']}],
  41. astring: ['melo', 'kaka', 'much', 'save']
  42. }
  43. var buf = Struct.pack(proto, msg);
  44. console.log(buf);
  45. var remsg = Struct.unpack(proto, buf);
  46. console.log(JSON.stringify(remsg));