我正在尋找一種方法來同步客戶端之間的時間,具有很好的精度(假設至少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)'。 –