简体   繁体   English

将应用程序时间与外部服务器时间同步的最佳方法是什么?

[英]What would be the best way to synchronize my application's time with outside server's time?

I was thinking of changing system's local time to server's time and then use it but I bet there are other ways to do this. 我当时在考虑将系统的本地时间更改为服务器的时间,然后再使用它,但是我敢肯定还有其他方法可以做到这一点。 I've been trying to find something like a clock in c#, but couldnt find anything. 我一直在尝试在c#中找到类似于时钟的内容,但找不到任何内容。 I'm receiving server's time in a DateTime format. 我正在以DateTime格式接收服务器的时间。

edit: I need my application to use while working same time server does. 编辑:我需要我的应用程序在服务器同时工作时使用。 I just want to get server's time once and after that, make my application work in a while loop using the time I've obtained from the server. 我只想获取服务器的时间,然后再使用从服务器获取的时间使应用程序在while循环中工作。 There might be a difference between my system's time and server's time (even 5 seconds) and that's why I want to do this. 我的系统时间和服务器时间(甚至5秒)之间可能会有差异,这就是为什么我要这样做。

It's not entirely clear what you mean, but you could certainly create your own IClock interface which you'd use everywhere in code, and then write an implementation of that which is regularly synchronized with your server (or with NTP). 你的意思并不完全清楚,但你当然可以创建自己的IClock接口,你可以在代码中的任何地方使用它,然后编写一个与你的服务器(或NTP)定期同步的实现。

My Noda Time project already uses the idea of an injectable clock - not for synchronization purposes, but for testability. 我的Noda Time项目已经使用了可注入时钟的想法-不是出于同步目的,而是出于可测试性。 (A time service is basically a dependency.) Basically the idea is workable :) You may well not find anything which already does this, but it shouldn't be too hard to write. (时间服务基本上是一种依赖。)基本上这个想法是可行的:)你可能找不到任何已经做到这一点的东西,但它写起来应该不会太难。 You'll want to think about how to adjust time though - for example, if the server time gets ahead of your "last server time + local time measurements" you may want to slew it gradually rather than having a discrete jump. 您可能想要考虑如何调整时间 - 例如,如果服务器时间超过“上次服务器时间+本地时间测量”,您可能希望逐渐转换它而不是进行离散跳转。

This is always assuming you do want it to be local to your application, of course. 当然,这始终是假设您确实希望它在应用程序本地。 Another alternative (which may well not be appropriate, depending on your context) is to require that the host runs a time synchronization client (I believe Windows does by default these days) and simply start failing if the difference between your server and the client gets too large. 另一种选择(可能不适合,具体取决于您的上下文)是要求主机运行时间同步客户端(我相信这些天Windows默认情况下会运行),并且如果服务器与客户端之间的差异有所增加,则只会开始失败太大了。 (It's never going to be exactly in sync anyway, or at least not for long - you'll need to allow for some leeway.) (无论如何,它永远不会完全同步,或者至少不会持续很长时间 - 你需要留出一些余地。)

The answer @JonSkeet's provided to synch the times looks good, I just wanted to point out some things. @JonSkeet提供的同步时间的答案看起来不错,我只想指出一些事情。

As @Alexei already said, users require admin privileges to be able to change their local time (in Windows as least), but there may also be other issues that can cause the time to be out of synch (bad internet connection, hacks etc.). 正如@Alexei已经说过的,用户需要管理员权限才能更改他们的本地时间(至少在Windows中),但是可能还有其他问题会导致时间不同步(糟糕的互联网连接,黑客攻击等)。 )。 This means there is no guarantee that the client time is indeed the same as the server time, so you will at least need to check the time the request was received serverside anyway. 这意味着不能保证客户端时间确实与服务器时间相同,因此无论如何您至少需要检查在服务器端收到请求的时间。 Plus there might also be a usability issue at hand here, would I want an application to be able change the time of my own local machine? 另外,这里可能还会有可用性问题,我是否希望应用程序能够更改自己本地计算机的时间? Hell no. 一定不行。

To sum things up: 总结一下:

  • Check the time of the request serverside at least 至少检查请求服务器端的时间
  • Don't change the time of the client machine but show some kind of indicator in your application 请勿更改客户端计算机的时间,但在应用程序中显示某种指示符

How to handle the indicator in your application can be done in various ways. 可以通过多种方式来处理应用程序中的指标。

  • Show a clock in your application (your initial idea) that is periodically synched with the server 在您的应用程序中显示一个时钟(您的最初想法),该时钟与服务器定期同步
  • Show some kind of countdown ( "you can submit after x seconds.." ), push a resetCountdown request to the clients when a request is received. 显示某种倒计时( “你可以在x秒后提交......” ),在收到请求时向客户端发送resetCountdown请求。
  • Enable a 'send button' or what ever you have, this would work kind of similar to the countdown. 启用“发送按钮”或任何你拥有的,这将有点类似于倒计时。

Just remember, it's nearly impossible validate a request such as this clientside. 请记住,验证这样的请求几乎是不可能的。 So you have to build in some checks serverside! 因此,您必须在服务器端建立一些检查!

I actually wanted to write a comment but it got kind of long.. :) 我实际上想写评论,但是它有点长.. :)

Okay a bit of necromancy as this is 6 years old, but had to deal with a similar problem for a network game. 好吧,因为它已经有6年历史了,但它不得不处理网络游戏的类似问题。

Employed a technique I referred to as "marco-polo" for reasons that will be obvious soon. 采用了一种我称之为“马可波罗”的技术,其原因很快就会显现出来。 It requires the two clocks to be able to exchange messages, and its accuracy is dependent on how fast they can do that. 它要求两个时钟能够交换消息,其准确性取决于它们能够以多快的速度完成。

Disclaimer: I am fairly certain I am not the first to do this, and that this is the most rudimentary way to synchronize two clocks. 免责声明:我可以肯定我不是第一个这样做的人,这是使两个时钟同步的最基本的方法。 Still I didn't find a documented way of doing so. 我仍然没有找到记录在案的方式。

At Clock B (The clock we're trying to synchronize) we do the following :: 在时钟B(我们试图同步的时钟),我们执行以下操作::

// Log the timestamp
localTime_Marco_Send = DateTime.UtcNow;

// Send that to clock A
SendSyncRequest();

// Wait for an answer
Sleep(..);

At Clock A (the reference clock) we have the following handler :: 在时钟A(参考时钟),我们有以下处理程序::

// This is triggered by SendSyncRequest
OnReceiveSyncRequest()
{
    // We received "Marco" - Send "Polo"
    SendSyncReply(DateTime.UtcNow);
}

And back at Clock B :: 回到时钟B ::

// This is triggered by SendSyncReply
OnReceiveSyncReply(DateTime remoteHalfTime)
{
    // Log the time we received it
    DateTime localTime_Polo_Receive = DateTime.UtcNow;

    // The remote time is somewhere between the two local times
    // On average, it will be in the middle of the two
    DateTime localHalfTime = localTime_Marco_Send  + 
         (localTime_Polo_Receive - localTime_Marco_Send) / 2;

    // As a result, the estimated dT from A to B is
    TimeSpan estimatedDT_A_B = localHalfTime - remoteHalfTime;
}

As a result we now have access to a nifty TimeSpan we can subtract from our current local time to estimate the remote time 结果,我们现在可以访问一个漂亮的TimeSpan,我们可以从当前本地时间中减去以估算远程时间

DateTime estimatedRemoteTime = DateTime.UtcNow - estimatedDT_A_B;

The accuracy of this estimate is subject to the Round Trip Time of send-receive-send-receive, and you should also account for Clock drift (you should be doing this more than once): 此估计的准确性取决于发送 - 接收 - 发送 - 接收的往返时间,您还应考虑时钟漂移(您应该多次执行此操作):

  1. Round-trip-time. 往返时间。 If it were instant, you'd have the exact dT. 如果是即时的,您将获得准确的dT。 If it takes 1 second to come and return, you don't know if the delay was on the sending or the receiving. 如果需要1秒钟才能返回,则您不知道延迟是在发送还是在接收上。 As a result, your error is 0 < e < RTT, and on average will be RTT/2. 因此,您的错误为0 <e <RTT,平均为RTT / 2。 If you know send (or receive) takes more than the other, use that to your advantage - the time you received is not the half-time, but is shifted relatively to how long each leg takes 如果你知道发送(或接收)比另一个更多,那么使用它对你有利 - 你收到的时间不是半场时间,而是相对于每条腿走多长时间
  2. Clock drift. 时钟漂移。 CPU clocks drift, maybe 1s per day. CPU时钟漂移,可能每天1次。 So poll again once potential drift may play an important role. 因此,一旦潜在漂移可能再次发挥重要作用,请再次进行轮询。

Your server should always save the time in UTC mode. 您的服务器应始终以UTC模式节省时间。
You save time in UTC like this in the server: 您可以在服务器中这样在UTC中节省时间:

  DateTime utcTime = new DateTime(0, DateTimeKind.Utc);

or: 要么:

    DateTime utcTimeNow = DateTime.UtcNow;

In the client, when you get the time which is stored in utc you can sonvert it to local time like this: 在客户端中,当您获取存储在utc中的时间时,可以将其转换为本地时间,如下所示:

    public DateTime ToLocalTime(DateTime utcTime)
    {
        //Assumes that even if utcTime kind is no properly deifned it is indeed UTC time
        DateTime serverTime= new DateTime(utcTime.Ticks, DateTimeKind.Utc);
        return TimeZoneInfo.ConvertTimeFromUtc(serverTime, m_localTimeZone);            
    }

If You want to change your local time zone , here is a code example on how to read time zone to use from config: 如果您想更改本地时区,下面是一个代码示例,说明如何从config中读取要使用的时区:

string localTimeZoneId = sysParamsHelper.ReadString(LOCAL_TIME_ZONE_ID_KEY, LOCAL_TIME_ZONE_DEFAULT_ID);
    ReadOnlyCollection<TimeZoneInfo> timeZones = TimeZoneInfo.GetSystemTimeZones();

    foreach (TimeZoneInfo timeZoneInfo in timeZones)
    {                
       if(timeZoneInfo.Id.Equals(localTimeZoneId))
       {
           m_localTimeZone = timeZoneInfo;
           break;
       }
    }

    if (m_localTimeZone == null)
    {
        m_logger.Error(LogTopicEnum.AMR, "Could not find time zone with id: " + localTimeZoneId + " . will use default time zone (UTC).");
        m_localTimeZone = TimeZoneInfo.Utc;
    }          

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 将XmlWriter访问同步到文件以防止IOExceptions的最佳方法是什么? - What's the best way to synchronize XmlWriter access to a file to prevent IOExceptions? 在运行时调整WinForms应用程序主窗体的起始大小和位置的最安全方法是什么? - What's the safest way to adjust my WinForms application main form starting size and position at run time? 对我的类属性值应用自定义格式的最佳方法是什么? - What's would be the best way to apply custom formatting for my class property values? 监视桌面应用程序的最佳方法是什么? - What's the best way to watchdog a desktop application? 如何获得外部服务器的时间(包括毫秒或(1/100秒))? - How to get outside server's time (including milliseconds or (1/100 s))? 检查服务器收到的第一条消息的最佳方法是什么? - What's the best way to check the first message that's received by the server? 更改架构后更新我的asp.net应用程序/数据库的最佳方法是什么? - What's the best way to update my asp.net application / database after changing the schema? 在企业和数据库之间同步日期时间的最佳方法 - best way to synchronize date time between business and database 知道这是应用程序第一次在当天开放的最佳方式是什么? - what is the best way to know if it is the first time that the application is open in the day? 在计算机/平板电脑/手机上运行的浏览器上显示存储在IIS服务器上的视频的最佳方法是什么 - What's the best way to display on a browser running on a computer/tablet/cell a video stored on my IIS server
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM