zone2.js 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. 'use strict';
  2. /**
  3. * 2个字节是16位(二进制),共能表示2^16=65536个数。但由于数是有符号的,最高位用作符号位,所以只有低15位表示绝对值。
  4. * 整型在内存中以补码存储,能表示的最大正整数是2^15-1=32767。
  5. */
  6. const net = require('node:net');
  7. const { Stick, MaxBodyLen } = require('@lvgithub/stick');
  8. const stick = new Stick(1024).setReadIntBE('32');
  9. stick.setMaxBodyLen(MaxBodyLen['2048M']);
  10. const LOCAL_PORT = 1936;
  11. /**
  12. * 头长度(Byte)
  13. */
  14. const HEAD_LEN = 4;
  15. /**
  16. * 标识长度(Byte)
  17. */
  18. const IDENTIFIER_LEN = 2;
  19. /**
  20. * 媒体服务器映射
  21. */
  22. const MEDIA_SERVER_MAP = new Map([
  23. ['9999', { port: 1935, host: '192.168.66.73' }],
  24. ]);
  25. /**
  26. * 媒体服务器连接池
  27. */
  28. const MEDIA_SERVER_POOLS = new Map();
  29. /**
  30. * 初始化多媒体服务器连接池
  31. */
  32. for (let [key, value] of MEDIA_SERVER_MAP) {
  33. const socket = net.createConnection({ host: value.host, port: value.port });
  34. MEDIA_SERVER_POOLS.set(key, socket);
  35. }
  36. /**
  37. * 关闭所有目标服务器连接
  38. */
  39. const closeAllTargetSocket = function () {
  40. for (let [, value] of MEDIA_SERVER_POOLS) {
  41. value.end();
  42. }
  43. };
  44. const proxy = net.createServer(function (socket) {
  45. socket.on('data', function (data) {
  46. stick.putData(data);
  47. });
  48. stick.onData(function (data) {
  49. const totalHeadLen = HEAD_LEN + IDENTIFIER_LEN;
  50. // 解析包头长度
  51. const head = Buffer.alloc(HEAD_LEN);
  52. data.copy(head, 0, 0, HEAD_LEN);
  53. const dataLen = head.readInt32BE() - IDENTIFIER_LEN;
  54. // 解析标识
  55. const identifier = Buffer.alloc(IDENTIFIER_LEN);
  56. data.copy(identifier, 0, HEAD_LEN, totalHeadLen);
  57. // 解析数据包内容
  58. const body = Buffer.alloc(dataLen);
  59. data.copy(body, 0, totalHeadLen, head.readInt32BE() + HEAD_LEN);
  60. const mediaId = identifier.readInt16BE() + '';
  61. console.log('data length: ' + dataLen);
  62. console.log('identifier content: ' + mediaId);
  63. // console.log('body content: ' + body.toString('hex'));
  64. if (MEDIA_SERVER_POOLS.has(mediaId)) {
  65. const mediaServer = MEDIA_SERVER_MAP.get(mediaId);
  66. console.log('matched media server: %s:%s', mediaServer.host, mediaServer.port);
  67. const targetSocket = MEDIA_SERVER_POOLS.get(mediaId);
  68. /** 测试代码START: 正式环境为一个代理网关对应多个媒体服务 */
  69. if (targetSocket.listeners('data').length === 0) {
  70. targetSocket.on('data', function (chunk) {
  71. // TODO 向客户端回写需要实现推送一样的逻辑
  72. socket.write(chunk);
  73. });
  74. }
  75. if (targetSocket.listeners('close').length === 0) {
  76. targetSocket.on('close', function () {
  77. socket.end();
  78. });
  79. }
  80. /** 测试代码END */
  81. targetSocket.write(body);
  82. } else {
  83. console.log('not match media server');
  84. }
  85. });
  86. socket.on('close', function () {
  87. closeAllTargetSocket();
  88. console.log('client disconnected');
  89. });
  90. socket.on('error', function (error) {
  91. console.log(`error:客户端异常断开: ${error}`);
  92. });
  93. });
  94. proxy.on('error', function (err) {
  95. throw err;
  96. });
  97. proxy.listen(LOCAL_PORT, function () {
  98. console.log('Zone2 proxy listening on ' + LOCAL_PORT);
  99. });