找回密码
 注册用户
查看: 266|回复: 0

[RMMZ] 【含MV】获取授时中心时间

[复制链接]

88

主题

7

回帖

1277

积分

资深会员

积分
1277
发表于 2024-6-12 16:52:59 | 显示全部楼层 |阅读模式
研究了一下 NTP 授时服务,MV/MZ 基于 nw.js 可以直接用。

UDP 协议丢包率挺高,真实场景里估计需要一些重试机制。

核心脚本来自 GitHub:https://github.com/luk3skyw4lker/node-ntp-sync

用法:(因为不是新手向,所以没有做 RM 封装,自行取用 response 的值)
  1. const NTP = window.NtpClient;
  2. const client = new NTP('ntp.ntsc.ac.cn',
  3.                 123,
  4.                 { timeout: 3000 });
  5. client
  6.   .syncTime()
  7.   .then(response => console.log('TIME:', response))
  8.   .catch(console.log);
复制代码
QQ图片20240612164924.png



脚本:

  1. (function(){
  2.         const udp = require('dgram');
  3.         function toMsecs(buffer, offset) {
  4.                 let seconds = 0;
  5.                 let fraction = 0;

  6.                 for (let i = 0; i < 4; ++i) {
  7.                         seconds = seconds * 256 + buffer[offset + i];
  8.                 }

  9.                 for (let i = 4; i < 8; ++i) {
  10.                         fraction = fraction * 256 + buffer[offset + i];
  11.                 }

  12.                 return seconds + fraction / Math.pow(2, 32);
  13.         }

  14.         const toFrac = ts => {
  15.                 return Math.floor(Math.abs(ts - Math.floor(ts)) * Math.pow(2, 32));
  16.         };

  17.         const sysToNTP = timestamp => timestamp + NTPPacket.NTP_DELTA;

  18.         const writeInMillis = (buffer, offset, ts, addDelta) => {
  19.                 const seconds = addDelta ? ts + NTP_DELTA : ts;
  20.                 const fraction = toFrac(ts);

  21.                 // seconds
  22.                 buffer[offset + 0] = (seconds & 0xff000000) >> 24;
  23.                 buffer[offset + 1] = (seconds & 0x00ff0000) >> 16;
  24.                 buffer[offset + 2] = (seconds & 0x0000ff00) >> 8;
  25.                 buffer[offset + 3] = seconds & 0x000000ff;

  26.                 // fraction
  27.                 buffer[offset + 4] = (fraction & 0xff000000) >> 24;
  28.                 buffer[offset + 5] = (fraction & 0x00ff0000) >> 16;
  29.                 buffer[offset + 6] = (fraction & 0x0000ff00) >> 8;
  30.                 buffer[offset + 7] = fraction & 0x000000ff;

  31.                 return buffer;
  32.         };

  33.         const MODES = {
  34.                 CLIENT: 3,
  35.                 SERVER: 4
  36.         };

  37.         const NTP_DELTA = 2208988800;

  38.         class NTPPacket {
  39.                 constructor(mode) {
  40.                         Object.assign(this, {
  41.                                 mode: mode || 4,
  42.                                 leap: 0,
  43.                                 version: 3,
  44.                                 stratum: 0,
  45.                                 poll: 0,
  46.                                 precision: 0,
  47.                                 rootDelay: 0,
  48.                                 rootDispersion: 0,
  49.                                 referenceId: 0,
  50.                                 referenceTimestamp: 0,
  51.                                 originateTimestamp: 0,
  52.                                 rxTimestamp: 0,
  53.                                 txTimestamp: 0
  54.                         });
  55.                 }

  56.                 static parse(data) {
  57.                         if (data.length < 48) {
  58.                                 throw new Error('Invalid NTP Package');
  59.                         }

  60.                         const packet = new NTPPacket(4);

  61.                         // Control bytes
  62.                         packet.leap = (data[0] >> 6) & 0x3;
  63.                         packet.version = (data[0] >> 3) & 0x7;
  64.                         packet.mode = data[0] & 0x7;
  65.                         packet.stratum = parseInt(data[1]) || 2;
  66.                         packet.poll = parseInt(data[2]) || 10;
  67.                         packet.precision = parseInt(data[3]);
  68.                         packet.rootDelay = data.slice(4, 8).readFloatBE(0) / 2 ** 16;
  69.                         packet.rootDispersion = data.slice(8, 12).readFloatBE(0) / 2 ** 16;
  70.                         packet.referenceId = data.slice(12, 16);

  71.                         // Timestamps where the 4 first bytes are the
  72.                         // int part and the 4 last are the frac part
  73.                         // const refTimestampHigh = data.slice(16, 20).readUint32BE();
  74.                         // const refTimestampLow = data.slice(20, 24).readFloatBE();
  75.                         packet.referenceTimestamp = toMsecs(data, 16);

  76.                         // const origTimestampHigh = data.slice(24, 28).readUint32BE();
  77.                         // const origTimestampLow = data.slice(28, 32).readUint32BE();
  78.                         packet.originateTimestamp = toMsecs(data, 24);

  79.                         // const rxTimestampHigh = data.slice(32, 36).readUint32BE();
  80.                         // const rxTimestampLow = data.slice(36, 40).readUint32BE();
  81.                         packet.rxTimestamp = toMsecs(data, 32);

  82.                         // const txTimestampHigh = data.slice(40, 44).readUint32BE();
  83.                         // const txTimestampLow = data.slice(44, 48).readUint32BE();
  84.                         packet.txTimestamp = toMsecs(data, 40);

  85.                         return packet;
  86.                 }

  87.                 bufferize(packet) {
  88.                         const buffer = Buffer.alloc(48).fill(0x00);

  89.                         buffer[0] = (packet.leap << 6) | (packet.version << 3) | (this.mode << 0);
  90.                         buffer[1] = packet.stratum;
  91.                         buffer[2] = packet.poll;
  92.                         buffer[3] = packet.precision;

  93.                         buffer.writeUInt32BE(packet.rootDelay, 4);
  94.                         buffer.writeUInt32BE(packet.rootDispersion, 8);
  95.                         buffer.writeUInt32BE(packet.referenceId, 12);

  96.                         // Reference Timestamp
  97.                         writeInMillis(buffer, 16, packet.referenceTimestamp, true);

  98.                         // Originate timestamp
  99.                         writeInMillis(
  100.                                 buffer,
  101.                                 24,
  102.                                 packet.originateTimestamp,
  103.                                 this.mode !== MODES.SERVER // Don't add NTP_DELTA if the packet is server mode
  104.                         );

  105.                         // RX Timestamp
  106.                         writeInMillis(buffer, 32, packet.rxTimestamp, true);

  107.                         // TX Timestamp
  108.                         writeInMillis(buffer, 40, packet.txTimestamp, true);

  109.                         return buffer;
  110.                 }
  111.         }

  112.         function createPacket() {
  113.                 const packet = new NTPPacket(MODES.CLIENT);

  114.                 packet.originateTimestamp = Math.floor(Date.now() / 1000);

  115.                 return packet.bufferize(packet);
  116.         }

  117.         function parse(buffer) {
  118.                 const message = NTPPacket.parse(buffer);

  119.                 message.destinationTimestamp = Math.floor(Date.now() / 1000) + NTP_DELTA;
  120.                 message.time = new Date(Math.floor((message.rxTimestamp - NTP_DELTA) * 1000));

  121.                 // Timestamp Name          ID   When Generated
  122.                 // ------------------------------------------------------------
  123.                 // Originate Timestamp     T1   time request sent by client
  124.                 // Receive Timestamp       T2   time request received by server
  125.                 // Transmit Timestamp      T3   time reply sent by server
  126.                 // Destination Timestamp   T4   time reply received by client
  127.                 const T1 = message.originateTimestamp;
  128.                 const T2 = message.rxTimestamp;
  129.                 const T3 = message.txTimestamp;
  130.                 const T4 = message.destinationTimestamp;

  131.                 // The roundtrip delay d and system clock offset t are defined as:
  132.                 // -
  133.                 // d = (T4 - T1) - (T3 - T2)     t = ((T2 - T1) + (T3 - T4)) / 2
  134.                 message.d = T4 - T1 - (T3 - T2);
  135.                 message.t = (T2 - T1 + (T3 - T4)) / 2;

  136.                 return message;
  137.         }

  138.         class Client {
  139.                 constructor(
  140.                         server = 'pool.ntp.org',
  141.                         port = 123,
  142.                         options = { timeout: 3000 }
  143.                 ) {
  144.                         this.server = server;
  145.                         this.port = port;
  146.                         this.socket = udp.createSocket('udp4');
  147.                         this.options = options;

  148.                         return this;
  149.                 }

  150.                 async syncTime() {
  151.                         return new Promise((resolve, reject) => {
  152.                                 this.socket = udp.createSocket('udp4');

  153.                                 const {
  154.                                         server,
  155.                                         port,
  156.                                         options: { timeout }
  157.                                 } = this;

  158.                                 const packet = createPacket();

  159.                                 this.socket.send(packet, 0, packet.length, port, server, err => {
  160.                                         if (err) {
  161.                                                 this.socket.close();
  162.                                                 return reject(err);
  163.                                         }

  164.                                         const timer = setTimeout(() => {
  165.                                                 const error = new Error(
  166.                                                         "NTP request timed out, server didn't answered"
  167.                                                 );
  168.                                                 this.socket.close();
  169.                                                 return reject(error);
  170.                                         }, timeout);

  171.                                         this.socket.once('message', data => {
  172.                                                 clearTimeout(timer);

  173.                                                 const message = parse(data);

  174.                                                 this.socket.close();

  175.                                                 return resolve(message);
  176.                                         });
  177.                                 });
  178.                         });
  179.                 }
  180.         }
  181.         window.NtpClient = Client;
  182. })();
复制代码


回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册用户

本版积分规则

Archiver|QQ群: 48625831|爱上RPG|哈库纳玛塔塔 |网站地图 Clicky

GMT+8, 2024-10-23 15:27 , Processed in 0.061368 second(s), 22 queries .

Powered by Discuz! X3.5

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表