program tip

클라이언트 측 자바 스크립트 시계를 서버 날짜와 동기화하는 가장 좋은 방법

radiobox 2020. 12. 24. 23:34
반응형

클라이언트 측 자바 스크립트 시계를 서버 날짜와 동기화하는 가장 좋은 방법


HTML 페이지에 고정 된 시간대 (MSK 또는 MSD-현재 날짜에 따라 다름)에 디지털 시계 (분 단위)를 표시하는 작업이 있습니다. 클라이언트 시스템 시계에 의존하는 것을 피하고 싶기 때문에 서버와의 동기화가 필요합니다. HTTP 서버는 각 응답에서 Date 헤더를 보내므로 사이트의 모든 URL에 AJAX GET 또는 HEAD 요청을 보내 서버 날짜를 가져오고 클라이언트 날짜와의 차이를 계산하고 setTimeout ()으로 시계를 업데이트 할 때 사용할 수 있습니다. 다른 문제가 남아 있습니다. 일광 설정을위한 시간대 전환, 매우 느린 연결을 고려한 대기 시간.

이 작업에 대한 가장 간단한 방법은 무엇입니까? 서버 측 프로그래밍없이 해결하고 싶습니다.


ajax를 사용하려는 경우 readyState == 2와 readyState == 3 사이의 클라이언트 시간을 기억해야합니다. 서버 시간은 요청 수신 시간과 응답 준비 시간 사이에 설정되기 때문입니다.


이 두 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.XMLHTTP"때문에 IE에서만 작동합니다.


코드에서 NTP (Network Time Protocol)정확한 시간을 계산할 수 있습니다 .

나는 당신을 위해 설명하려고 :

  1. 요청을 보낼 때 ClientTime이 있습니다 (예 : 2012 년 4 월 3 일 13 : 56 : 10.123).
  2. ClientTime을 서버로 보냅니다.
  3. 우리는이 왕복 시간을 내가 그것을라고 요청 RequestTime (예 : 그것은 5 초 소요)
  4. 서버에서 서버와 클라이언트 간의 차이 시간을 계산합니다 (예 : It ServerTime-ClientTime = ServerClientDifferenceTimeWithRequestTime), 이제 3 단계의 왕복 요청 시간을 포함하여이 차이를 계산 한 다음 차이에서 왕복 시간을 제거해야합니다.
  5. ServerClientDifferenceTimeWithRequestTime 및 ServerTime을 포함하는 서버 전송 응답
  6. 우리는이 왕복 시간을 응답, 내가 그것을라는 RESPONSETIME (예 : 그것은 3 초 소요)
  7. 클라이언트에서 서버와 클라이언트 간의 차이 시간을 다시 계산합니다 (예 : It ServerTime-ClientTime = ServerClientDifferenceTimeWithResponseTime). 이제 6 단계의 왕복 응답 시간을 포함하여이 차이를 계산해야합니다.
  8. 우리는 지금 클라이언트에 시간이 있습니다
  9. 클라이언트에서 간단한 방정식을 계산해야합니다.

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}";

씨#:

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);
});

위의 @ 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)));
    }
});

서버 측 (php,하지만 무엇이든 가능) :

Your server at route 'GET /ntp' should return something like:

echo (string) round(microtime(true) * 1000);

If you have PHP >5.4, then you can save a call to microtime() and make it a bit more accurate with:

echo (string) round($_SERVER['REQUEST_TIME_FLOAT'] * 1000);

NOTE

This way might be seen as kind of ghetto, there are some other Stack Overflow answers that could guide you towards a better solution:


I'd only request the update from the server every 30s or so, if you require precision only to the minute. Don't rely on the client time at all, but use their system clock to keep the clock accurate between updates. I think you answered your own question?

It would help if we better understood what you're actually trying to do.

If you simply want a clock to display the time on the server, which is then adjusted to a certain timezone, do it clientside with offsets. Handle DST in the timezones it is applicable by using the date you receive from the server as well. If you want to determine latency, you would probably need a small script on the server to calculated the difference. But as above, it would help to understand the problem better. If precision is only to the minute, latency seems less critical.


Thanks to @Mehdi Yeganeh and @Fedearne. I implement my function to use both logic and it's work.

https://gist.github.com/ethaizone/6abb1d437dbe406fbed6


I would sync the time during initialization with Internet Time Server.

http://tf.nist.gov/service/its.htm

ReferenceURL : https://stackoverflow.com/questions/1638337/the-best-way-to-synchronize-client-side-javascript-clock-with-server-date

반응형