C# 同步我的应用程序';与外部服务器的时间';什么时候了?

C# 同步我的应用程序';与外部服务器的时间';什么时候了?,c#,synchronization,clock,C#,Synchronization,Clock,我曾考虑将系统的本地时间更改为服务器时间,然后使用它,但我打赌还有其他方法可以做到这一点。我一直想在c#中找到一个类似时钟的东西,但什么也找不到。我正在以日期时间格式接收服务器的时间 编辑: 我需要我的应用程序在服务器工作的同时使用。我只想获得一次服务器的时间,然后使用从服务器获得的时间使我的应用程序在while循环中工作。我的系统时间和服务器时间之间可能存在差异(甚至5秒),这就是我想这样做的原因。不完全清楚您的意思,但您当然可以创建自己的IClock界面,在代码中的任何地方都可以使用它,然后

我曾考虑将系统的本地时间更改为服务器时间,然后使用它,但我打赌还有其他方法可以做到这一点。我一直想在c#中找到一个类似时钟的东西,但什么也找不到。我正在以日期时间格式接收服务器的时间

编辑:
我需要我的应用程序在服务器工作的同时使用。我只想获得一次服务器的时间,然后使用从服务器获得的时间使我的应用程序在while循环中工作。我的系统时间和服务器时间之间可能存在差异(甚至5秒),这就是我想这样做的原因。

不完全清楚您的意思,但您当然可以创建自己的
IClock
界面,在代码中的任何地方都可以使用它,然后编写一个与服务器(或NTP)定期同步的实现

我的项目已经使用了可注入时钟的概念——不是为了同步,而是为了可测试性。(时间服务基本上是一种依赖关系。)基本上这个想法是可行的:)你很可能找不到任何已经做到这一点的东西,但写起来应该不会太难。不过,您需要考虑如何调整时间——例如,如果服务器时间超过了“上一次服务器时间+本地时间测量”,您可能希望逐渐调整时间,而不是进行离散跳跃


当然,这总是假设您确实希望它位于应用程序的本地。另一种选择(这可能不太合适,取决于您的上下文)是要求主机运行一个时间同步客户端(我相信Windows现在默认会这样做),如果您的服务器和客户端之间的差异太大,则直接开始失败。(无论如何,它永远不会完全同步,或者至少不会同步很长时间-您需要留出一些余地。)

您的服务器应该始终在UTC模式下节省时间。
您可以在服务器中以UTC格式节省时间,如下所示:

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

在客户端中,当您获得存储在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);            
    }
如果您想更改本地时区,下面是一个关于如何从配置中读取要使用的时区的代码示例:

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;
    }          
string localTimeZoneId=sysParamsHelper.ReadString(本地\u时区\u ID\u键,本地\u时区\u默认\u ID);
ReadOnlyCollection timeZones=TimeZoneInfo.GetSystemTimeZones();
foreach(时区信息时区信息)
{                
if(timeZoneInfo.Id.Equals(localTimeZoneId))
{
m_localTimeZone=timeZoneInfo;
打破
}
}
if(m_localTimeZone==null)
{
m_logger.Error(LogTopicEnum.AMR,“找不到id为“+localTimeZoneId+”的时区。将使用默认时区(UTC)。”;
m_localTimeZone=TimeZoneInfo.Utc;
}          

JonSkeet为同步《泰晤士报》提供的答案看起来不错,我只是想指出一些事情

正如@Alexei已经说过的,用户需要管理员权限才能更改他们的本地时间(至少在Windows中),但也可能有其他问题会导致时间不同步(互联网连接不良、黑客攻击等)。这意味着不能保证客户端时间确实与服务器时间相同,因此您至少需要检查服务器端收到请求的时间。此外,这里可能还有一个可用性问题,我是否希望应用程序能够更改我自己本地机器的时间?他妈的不

总而言之:

  • 至少检查请求服务器端的时间
  • 不要更改客户端计算机的时间,但在应用程序中显示某种指示器
如何处理应用程序中的指示器可以通过多种方式完成

  • 在应用程序中显示与服务器定期同步的时钟(您最初的想法)
  • 显示某种类型的倒计时(“您可以在x秒后提交…”),在收到请求时将重置倒计时请求推送到客户端
  • 启用“发送按钮”或任何你有的东西,这将类似于倒计时
请记住,像这样的客户端验证请求几乎是不可能的。因此,您必须在服务器端构建一些检查


我真的想写一篇评论,但有点长……)

好吧,这已经6岁了,需要一点巫术,但在一款网络游戏中也遇到了类似的问题

采用了一种我称之为“马可波罗”的技术,原因很快就会显而易见。它要求两个时钟能够交换信息,其准确性取决于它们交换信息的速度

免责声明:我相当肯定我不是第一个这样做的人,这是同步两个时钟最基本的方法。但我还是没有找到一个有文件证明的方法

在时钟B(我们尝试同步的时钟)处,我们执行以下操作:

// Log the timestamp
localTime_Marco_Send = DateTime.UtcNow;

// Send that to clock A
SendSyncRequest();

// Wait for an answer
Sleep(..);
在时钟A(参考时钟)处,我们有以下处理程序:

// This is triggered by SendSyncRequest
OnReceiveSyncRequest()
{
    // We received "Marco" - Send "Polo"
    SendSyncReply(DateTime.UtcNow);
}
回到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;
}
因此,我们现在可以访问一个漂亮的时间跨度,我们可以从当前本地时间中减去它来估计远程时间

DateTime estimatedRemoteTime = DateTime.UtcNow - estimatedDT_A_B;
此估计的准确性取决于发送-接收的往返时间,您还应考虑时钟漂移(您应多次这样做):

  • 往返时间。如果它是即时的,你会得到确切的dT。如果到达并返回需要1秒的时间,您不知道延迟是在发送还是在接收上。因此,您的错误为0
  • 时钟漂移。CPU时钟漂移,可能是1s pe
    DateTime estimatedRemoteTime = DateTime.UtcNow - estimatedDT_A_B;