programing

클라이언트 측 Javascript 클럭을 서버 날짜와 동기화하는 가장 좋은 방법

oldcodes 2023. 3. 5. 10:24
반응형

클라이언트 측 Javascript 클럭을 서버 날짜와 동기화하는 가장 좋은 방법

일정 시간대(MSK 또는 MSD - 현재 날짜에 따라 다름)에서 HTML 페이지에 디지털 클럭(분 단위 정밀도)을 표시하는 작업이 있습니다.클라이언트 시스템 클럭에 의존하는 것을 피하고 싶기 때문에 서버와의 동기화가 필요합니다.HTTP 서버는 각 응답으로 Date 헤더를 송신하기 때문에 AJAX GET 또는 HEAD 요구를 사이트의 임의의 URL로 송신하여 서버 날짜를 취득하고 클라이언트 날짜와의 차이를 계산하여 setTimeout()으로 클럭을 갱신할 때 사용할 수 있습니다.또 다른 문제가 남아 있습니다.일광 설정의 타임존 스위칭, 매우 느린 접속의 레이텐시 어카운팅입니다.

이 작업에 대한 가장 간단한 방법이 있나요?서버 측 프로그래밍 없이 해결하고 싶습니다.

코드의 NTP(Network Time Protocol)를 사용하여 정확한 시간을 계산할 수 있습니다.

제가 설명해 드릴게요.

  1. 요청 전송 시 Client Time이 있습니다(예: 2012년 4월 3일 13:56:10.123).
  2. Client Time을 서버로 전송
  3. 요청에는 라운드 트립 시간이 있습니다.Request Time이라고 부릅니다(예:5초 걸립니다)
  4. 서버에서는 서버와 클라이언트 간의 차이 시간을 계산합니다(예:It ServerTime - ClientTime = ServerClientDifferenceTimeWithRequestTime)에서 3단계의 왕복 요청 시간을 포함하여 이 차이를 제거한 후 차이에서 왕복 시간을 제거해야 합니다.
  5. ServerClientDifferenceTimeWithRequestTime및ServerTime을포함한서버송신응답
  6. 응답에는 라운드 트립 시간이 있습니다. 시간을 Response Time이라고 부릅니다(예:소요시간은 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}";

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

메모

이 방법은 일종의 게토처럼 보일 수 있으며, 더 나은 솔루션으로 안내할 수 있는 스택 오버플로우 답변이 몇 가지 있습니다.

서버 시간은 요청 수신 시간과 응답 준비 시간 사이에 설정되므로 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가지 값밖에 없다.

  1. 클라이언트 시간Request 송신일
  2. 서버 시간
  3. 클라이언트 시간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

반응형