我正在寻找一种方法来同步客户端之间的时间,具有很好的精度(假设至少0.5秒)。同步时间在javascript中以很好的精度(> 0.5s)(类似于NTP)
由于精度较差(一秒或更少),我排除了使用jsontime或利用服务器响应头中的时间戳。
更新: 它应该工作,即使移动连接。这并非罕见(例如在意大利),3G连接本身的往返时间大约为0.5s,因此算法必须非常强大。
我正在寻找一种方法来同步客户端之间的时间,具有很好的精度(假设至少0.5秒)。同步时间在javascript中以很好的精度(> 0.5s)(类似于NTP)
由于精度较差(一秒或更少),我排除了使用jsontime或利用服务器响应头中的时间戳。
更新: 它应该工作,即使移动连接。这并非罕见(例如在意大利),3G连接本身的往返时间大约为0.5s,因此算法必须非常强大。
度假去旧好ICMP Timestamp消息方案。在JavaScript和PHP中实现相当简单。
下面是使用JavaScript和PHP该方案的实现:
// browser.js
var request = new XMLHttpRequest();
request.onreadystatechange = readystatechangehandler;
request.open("POST", "http://www.example.com/sync.php", true);
request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
request.send("original=" + (new Date).getTime());
function readystatechangehandler() {
var returned = (new Date).getTime();
if (request.readyState === 4 && request.status === 200) {
var timestamp = request.responseText.split('|');
var original = + timestamp[0];
var receive = + timestamp[1];
var transmit = + timestamp[2];
var sending = receive - original;
var receiving = returned - transmit;
var roundtrip = sending + receiving;
var oneway = roundtrip/2;
var difference = sending - oneway; // this is what you want
// so the server time will be client time + difference
}
}
现在的sync.php
代码:
<?php
$receive = round(microtime(true) * 1000);
echo $_POST["original"] . '|';
echo $receive . '|';
echo round(microtime(true) * 1000);
?>
我没有测试上面的代码,但它应该工作。
注意:如果发送和接收消息的实际时间相同或接近相同,以下方法将准确计算客户端和服务器之间的时间差。考虑以下情形:
Time Client Server
-------- -------- --------
Original 0 2
Receive 3 5
Transmit 4 6
Returned 7 9
使用这些数据,我们可以计算出:
Sending = Receive - Original = 5 - 0 = 5
Receiving = Returned - Transmit = 7 - 6 = 1
Roundtrip = Sending + Receiving = 5 + 1 = 6
正如你可以看到从上面的发送和接收时间计算不正确,这取决于客户端和服务器多少钱了同步。然而,往返时间总是正确的,因为我们首先添加两个单位(接收+原始),然后减去两个单位(返回 - 传输)。
如果我们假定单向时间总是的往返时间的一半(即,发送时间是接收所述时间,那么我们可以很容易地计算时间差如下):
Oneway = Roundtrip/2 = 6/2 = 3
Difference = Sending - Oneway = 5 - 3 = 2
作为你可以看到,我们准确地计算出了2个单位的时差。时间差的等式始终为sending - oneway
时间。然而,这个方程的准确性取决于你计算单向时间的准确度。如果发送和接收消息的实际时间不相等或大致相等,则需要找到其他方式来计算单向时间。但是,为了您的目的,这应该就足够了。
如果您只是想在多台电脑上同步时钟,NTP本身建议使用setting up your own timeserver。
建立一个API端点服务器上 即
http://localhost:3000/api/time
回报:
status: 200,
body: { time: {{currentTime}} }
如何做到这一点,将取决于你是后端语言使用。
给出了这样的端点,这个JS代码片段我扔会
var offsets = [];
var counter = 0;
var maxTimes = 10;
var beforeTime = null;
// get average
var mean = function(array) {
var sum = 0;
array.forEach(function (value) {
sum += value;
});
return sum/array.length;
}
var getTimeDiff = function() {
beforeTime = Date.now();
$.ajax('/api/time', {
type: 'GET',
success: function(response) {
var now, timeDiff, serverTime, offset;
counter++;
// Get offset
now = Date.now();
timeDiff = (now-beforeTime)/2;
serverTime = response.data.time-timeDiff;
offset = now-serverTime;
console.log(offset);
// Push to array
offsets.push(offset)
if (counter < maxTimes) {
// Repeat
getTimeDiff();
} else {
var averageOffset = mean(offsets);
console.log("average offset:" + averageOffset);
}
}
});
}
// populate 'offsets' array and return average offsets
getTimeDiff();
您可以使用此计算偏移(只需将其添加到本地时间),确定从每个客户的情况下常见的“万能”的时间。
这很有用,谢谢。使用中位数而不是均值来拒绝异常值也可能是有意义的。 – Groo
如何从JavaScript发送ICMP数据包?我只看到一个名为ActiveSocket的ActiveX来发送ICMP数据包,但我不能使用ActiveX。它在webkit上工作。 – micred
您不发送ICMP数据包。您只需使用ICMP用于同步服务器和客户端上的时间的相同方法即可。希望清除你的怀疑。干杯。 ;) –
你在PHP中的格式看起来不正确:不带参数的'microtime()'返回一个形式为“0.uuuuuu ssssssssss”的字符串。我宁愿'回响(microtime(true)* 1000)'。 –