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