클라이언트 측 Javascript 클럭을 서버 날짜와 동기화하는 가장 좋은 방법
일정 시간대(MSK 또는 MSD - 현재 날짜에 따라 다름)에서 HTML 페이지에 디지털 클럭(분 단위 정밀도)을 표시하는 작업이 있습니다.클라이언트 시스템 클럭에 의존하는 것을 피하고 싶기 때문에 서버와의 동기화가 필요합니다.HTTP 서버는 각 응답으로 Date 헤더를 송신하기 때문에 AJAX GET 또는 HEAD 요구를 사이트의 임의의 URL로 송신하여 서버 날짜를 취득하고 클라이언트 날짜와의 차이를 계산하여 setTimeout()으로 클럭을 갱신할 때 사용할 수 있습니다.또 다른 문제가 남아 있습니다.일광 설정의 타임존 스위칭, 매우 느린 접속의 레이텐시 어카운팅입니다.
이 작업에 대한 가장 간단한 방법이 있나요?서버 측 프로그래밍 없이 해결하고 싶습니다.
코드의 NTP(Network Time Protocol)를 사용하여 정확한 시간을 계산할 수 있습니다.
제가 설명해 드릴게요.
- 요청 전송 시 Client Time이 있습니다(예: 2012년 4월 3일 13:56:10.123).
- Client Time을 서버로 전송
- 요청에는 라운드 트립 시간이 있습니다.Request Time이라고 부릅니다(예:5초 걸립니다)
- 서버에서는 서버와 클라이언트 간의 차이 시간을 계산합니다(예:It ServerTime - ClientTime = ServerClientDifferenceTimeWithRequestTime)에서 3단계의 왕복 요청 시간을 포함하여 이 차이를 제거한 후 차이에서 왕복 시간을 제거해야 합니다.
- ServerClientDifferenceTimeWithRequestTime및ServerTime을포함한서버송신응답
- 응답에는 라운드 트립 시간이 있습니다.이 시간을 Response Time이라고 부릅니다(예:소요시간은 3초입니다.
- 클라이언트에서는 서버와 클라이언트 간의 차이 시간을 다시 계산합니다(예:It ServerTime - ClientTime = ServerClientDifferenceTimeWithResponseTime)도 마찬가지입니다. 이제 6단계에서 왕복 응답 시간을 포함하여 이 차이를 확인해야 합니다.
- 클라이언트에 지금 시간이 있다
- 클라이언트에서 간단한 방정식을 계산해야 합니다.
X(동기 시간) =Now + (ServerClientDifferenceTimeWithRequestTime - RquestTime)
X(동기 시간) =Now + (ServerClientDifferenceTimeWithResponseTime - ResponseTime)
Now - ClientTime = RquestTime + ResponseTime
=
Now - (ServerClientDiffRq - RquestTime) = Now - (ServerClientDiffRs - ResponseTime)
문제를 해결하면 다음과 같은 결과가 나옵니다.
ResponseTime = (ServerClientDifferenceTimeWithRequestTime - Now + ClientTime + - ServerClientDifferenceTimeWithResponseTime )/2
다음으로 클라이언트의 동기 시각 또는 서버 시각을 다음 식으로 확인할 수 있습니다.
X(동기 시간) =Now + (ServerClientDifferenceTimeWithResponseTime - ResponseTime)
간단한 코드를 보여주지만 쓰고 싶을 때는 UTC 날짜 및 시간 함수를 사용하는 것을 잊지 마세요.
서버측(예를 들어 php, c#):
PHP:
header('Content-Type: application/json; charset=utf-8');
$clientTime = $_GET["ct"] * 1; //for php 5.2.1 or up: (float)$_GET["ct"];
$serverTimestamp = round(microtime(true)*1000); // (new DateTime())->getTimestamp();
$serverClientRequestDiffTime = $serverTimestamp - $clientTime;
echo "{\"diff\":$serverClientRequestDiffTime,\"serverTimestamp\":$serverTimestamp}";
C#:
long clientTime = long.Parse(Request.Form["ct"]);
long serverTimestamp = (DateTime.Now.Ticks-(new DateTime(1970,1,1) - DateTime.MinValue).Ticks) / 10000;
long serverClientRequestDiffTime = serverTimestamp - clientTime;
Response.Write("{\"diff\":"+serverClientRequestDiffTime+",\"serverTimestamp\":"+serverTimestamp+"}");
클라이언트 측(Javascript with Jquery):
var clientTimestamp = (new Date()).valueOf();
$.getJSON('http://yourhost.com/getdatetimejson/?ct='+clientTimestamp, function( data ) {
var nowTimeStamp = (new Date()).valueOf();
var serverClientRequestDiffTime = data.diff;
var serverTimestamp = data.serverTimestamp;
var serverClientResponseDiffTime = nowTimeStamp - serverTimestamp;
var responseTime = (serverClientRequestDiffTime - nowTimeStamp + clientTimestamp - serverClientResponseDiffTime )/2
var syncedServerTime = new Date((new Date()).valueOf() + (serverClientResponseDiffTime - responseTime));
alert(syncedServerTime);
});
이 두 가지 Javascript 함수가 당신에게 도움이 될 것입니다.
var offset = 0;
function calcOffset() {
var xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
xmlhttp.open("GET", "http://stackoverflow.com/", false);
xmlhttp.send();
var dateStr = xmlhttp.getResponseHeader('Date');
var serverTimeMillisGMT = Date.parse(new Date(Date.parse(dateStr)).toUTCString());
var localMillisUTC = Date.parse(new Date().toUTCString());
offset = serverTimeMillisGMT - localMillisUTC;
}
function getServerTime() {
var date = new Date();
date.setTime(date.getTime() + offset);
return date;
}
편집: ".replace(/^(.)[\s\S]/"$1"" 삭제
calcOffset()은 서버 시간에서 오프셋을 계산하여 GMT/UTC를 보정합니다.
getServerTime(): 로컬 시간대를 사용하여 서버에 일치하는 로컬 시간 오프셋을 가져옵니다.
calcOffset()이 실행되는 데 시간이 걸리는 경우 몇 초간의 정밀도가 저하될 수 있습니다.실행 시간을 고려할 수 있을 것 같습니다.
현지시간 또는 서버시간 중 하나가 여름시간으로 변경되었을 때 또는 여름시간에서 변경되었을 때 계산된 오프셋이 잘못될 우려가 있는 경우 클럭 아워마다 리틀을 재계산할 수 있습니다.시스템은 데이릿 절약시간 변경을 보상합니다.로컬 클럭과 서버 클럭이 모두1시간이 경과할 때까지 기다려야 할 수 있습니다.
이 예는 "Msxml2" 때문에 IE에서만 작동합니다.XMLHTTP"라고 생각합니다.
위의 @mehdi-yeganeh 알고리즘은 도움이 되지 않았지만 NTP 알고리즘(또는 적어도 그 약한 버전)을 사용하여 서버와 클라이언트의 클럭을 동기화한다는 아이디어는 타당합니다.
이것이 저의 최종 구현입니다.서버 응답 헤더를 사용할 수 있는 경우 사용합니다(잘못된 경우 정정해 주십시오.자신의 테스트에서는 이것이 매우 정확하다고 합니다).
브라우저 측(스크립트 표시):
// the NTP algorithm
// t0 is the client's timestamp of the request packet transmission,
// t1 is the server's timestamp of the request packet reception,
// t2 is the server's timestamp of the response packet transmission and
// t3 is the client's timestamp of the response packet reception.
function ntp(t0, t1, t2, t3) {
return {
roundtripdelay: (t3 - t0) - (t2 - t1),
offset: ((t1 - t0) + (t2 - t3)) / 2
};
}
// calculate the difference in seconds between the client and server clocks, use
// the NTP algorithm, see: http://en.wikipedia.org/wiki/Network_Time_Protocol#Clock_synchronization_algorithm
var t0 = (new Date()).valueOf();
$.ajax({
url: '/ntp',
success: function(servertime, text, resp) {
// NOTE: t2 isn't entirely accurate because we're assuming that the server spends 0ms on processing.
// (t1 isn't accurate either, as there's bound to have been some processing before that, but we can't avoid that)
var t1 = servertime,
t2 = servertime,
t3 = (new Date()).valueOf();
// we can get a more accurate version of t2 if the server's response
// contains a Date header, which it generally will.
// EDIT: as @Ariel rightly notes, the HTTP Date header only has
// second resolution, thus using it will actually make the calculated
// result worse. For higher accuracy, one would thus have to
// return an extra header with a higher-resolution time. This
// could be done with nginx for example:
// http://nginx.org/en/docs/http/ngx_http_core_module.html
// var date = resp.getResponseHeader("Date");
// if (date) {
// t2 = (new Date(date)).valueOf();
// }
var c = ntp(t0, t1, t2, t3);
// log the calculated value rtt and time driff so we can manually verify if they make sense
console.log("NTP delay:", c.roundtripdelay, "NTP offset:", c.offset, "corrected: ", (new Date(t3 + c.offset)));
}
});
server-side(서버측) (다만, 모든 것을 사용할 수 있습니다.
루트 'GET / ntp'의 서버는 다음과 같은 것을 반환해야 합니다.
echo (string) round(microtime(true) * 1000);
PHP > 5.4 의 경우는, 콜을 microtime() 에 보존해, 다음의 조작으로 보다 정확하게 할 수 있습니다.
echo (string) round($_SERVER['REQUEST_TIME_FLOAT'] * 1000);
메모
이 방법은 일종의 게토처럼 보일 수 있으며, 더 나은 솔루션으로 안내할 수 있는 스택 오버플로우 답변이 몇 가지 있습니다.
- javascript 카운트다운과 서버 시간을 동기화하는 방법
- 여러 디바이스 간의 JS 시간 동기화
- 특히 이 솔루션은 여러 번 제공되었습니다.https://github.com/NodeGuy/ServerDate이것은 셋업에는 조금 더 많은 작업이 필요한 것 같지만 정확도가 향상될 것입니다.
서버 시간은 요청 수신 시간과 응답 준비 시간 사이에 설정되므로 Ajax를 사용하려면 readyState==2와 readyState==3 사이의 클라이언트 시간을 기억해야 합니다.
@Mehdi Yeganeh와 @Fedearne 덕분입니다.저는 논리와 일을 모두 사용하는 기능을 구현합니다.
https://gist.github.com/ethaizone/6abb1d437dbe406fbed6
만약 당신이 1분까지 정확성을 필요로 한다면, 나는 매 30대마다 서버에 업데이트를 요청할 것입니다.클라이언트 시각에 전혀 의존하지 말고 시스템 클럭을 사용하여 업데이트 간에 정확한 클럭을 유지합니다.네 질문에 답한 것 같은데?
당신이 실제로 무엇을 하려는지 우리가 더 잘 이해한다면 도움이 될 거예요.
단순히 클럭이 서버상의 시각을 표시하도록 하고, 그 후에 특정 타임존으로 조정하도록 하는 경우는, 오프셋을 사용해 클라이언트측에서 실시합니다.서버로부터 수신한 날짜도 사용하고, 적용 가능한 시간대로 DST 를 처리합니다.지연 시간을 판별하려면 서버에 작은 스크립트가 있어야 합니다.하지만 위와 같이 문제를 더 잘 이해하는 데 도움이 될 것입니다.정밀도가 분 단위일 경우 지연 시간이 덜 중요한 것으로 보입니다.
조금 늦었지만 이것이 누군가에게 도움이 되기를 바랍니다!
클라이언트 머신에 관계없이 서버 클럭을 표시해야 하는 경우도 있었습니다.기본적으로 여기서는 3가지 파라미터를 사용합니다.
x = clientReqTimestamp = (new Date()).valueOf(); //Client Timestamp at request.
y = serverTimestamp; //query your server for Unix Timestamp.
z = clientRespTimestamp = (new Date()).valueOf(); //Client Timestamp on receiving response.
그런 다음 다음 다음 계산을 수행합니다.
var reqElapsed = Math.abs(y - x); //time taken in milliseconds to hit the server
var respElapsed = Math.abs(z - y); //time taken in milliseconds to get response from server
var serverNewTime = z + respElapsed; // Voila! actual server time.
동작하고 있는 코드는 다음과 같습니다.
<script>
var clientTimestamp = (new Date()).valueOf();
var Data = {
OperatorMobileNo: 'XXXXXXXXXX',
requestClientTime: clientTimestamp
};
$.ajax({
type: "POST",
url: serviceURLx + "/XXXX/GetServerDateTime/1.0",
dataType: "JSON",
data: JSON.stringify(Data),
contentType: "application/json; charset=utf-8",
success: function (responseData) {
debugger;
var responseJSON = JSON.parse(JSON.stringify(responseData));
if (responseJSON.ResponseCode === "000") {
var x = clientReqTimestamp = clientTimestamp;
// If server time is in seconds => multiply by 1000 to convert sec to milli
var y = serverTimestamp = responseJSON.Response.ServTimestamp * 1000;
var z = clientRespTimestamp = (new Date()).valueOf();
var reqElapsed = Math.abs(y - x);
var respElapsed = Math.abs(z - y);
var serverNewTime = z + respElapsed;
debugger;
//Init Server Clock
setInterval( function() {
debugger;
var servClockT = new Date(serverNewTime += 1000);
document.getElementById('serverClock').innerHTML = servClockT;
}, 1000);
}
else {
swal("", "Unable To Fetch Server Time!", "info");
console.log(responseJSON.ResponseCode);
}
},
error: function () {
}
});
</script>
내가 질문을 정확히 이해했다면 우리는 3가지 값밖에 없다.
- 클라이언트 시간Request 송신일
- 서버 시간
- 클라이언트 시간Response
요청과 응답 시간이 동일하다고 가정할 경우 다음과 같이 서버와 클라이언트 간의 시간 차이를 계산할 수 있습니다.
const diff = serverTime - clientTimeWhenRequestSent
- (clientTimeWhenResponseReceived - clientTimeWhenRequestSent)/2;
고객의 정확한 시각을 얻을 수 있습니다.
const correctClienTime = (new Date()).valueOf() + diff;
초기화 중 시간을 인터넷 타임 서버와 동기화합니다.
http://tf.nist.gov/service/its.htm
언급URL : https://stackoverflow.com/questions/1638337/the-best-way-to-synchronize-client-side-javascript-clock-with-server-date
'programing' 카테고리의 다른 글
현과 목록을 구별하는 버마교적 방법은 무엇인가요? (0) | 2023.03.05 |
---|---|
Map 내의 null 값과 bean 내의 null 필드가 Jackson을 통해 직렬화되지 않도록 하는 방법 (0) | 2023.03.05 |
스프링 부트에서 여러 디스패처 서블릿/웹 컨텍스트 사용 (0) | 2023.03.05 |
React.js의 OnClick 이벤트 바인딩 (0) | 2023.03.05 |
wordpress $wpdb에서 마지막으로 삽입된 ID 가져오기 (0) | 2023.03.05 |