C# 对于.NET应用程序,最稳定的时间戳源是什么? 基本问题
我的C#申请中有一个时间戳问题。我从远程TCP连接异步接收数据。每次收到数据时,我都会将时间戳变量更新为C# 对于.NET应用程序,最稳定的时间戳源是什么? 基本问题,c#,datetime,C#,Datetime,我的C#申请中有一个时间戳问题。我从远程TCP连接异步接收数据。每次收到数据时,我都会将时间戳变量更新为DateTime.Now。在一个单独的线程上,我每秒检查一次,从上次接收以来,它是否已超过预定义的超时时间,如果是,则断开连接。这种方法已经工作了很多年,但是现在我遇到了这样一种情况,应用程序安装在一台时间源不稳定的机器上。每隔几天,机器时间就会“自动更正”,我会过早地断开连接。代码基本如下: 接收过程 检查过程 我在发布期间有有效的Wireshark捕获,就在断开连接之前,我看到NTP流量在
DateTime.Now
。在一个单独的线程上,我每秒检查一次,从上次接收以来,它是否已超过预定义的超时时间,如果是,则断开连接。这种方法已经工作了很多年,但是现在我遇到了这样一种情况,应用程序安装在一台时间源不稳定的机器上。每隔几天,机器时间就会“自动更正”,我会过早地断开连接。代码基本如下:
接收过程
检查过程
我在发布期间有有效的Wireshark捕获,就在断开连接之前,我看到NTP流量在至少1分钟的纠正中达到高潮。这显然会导致检查过程失败
技术细节/对预期问题的回答
DateTime.UtcNow
而不是DateTime.Now,因为性能原因。这不会影响问题本身
Environment.TickCount
和Stopwatch.GetTimestamp()
Environment.TickCount
可能会受到时间调整的影响,但我不确定在什么情况下。此外,由于我在其他更高性能的环境中使用了相同的方法,因此10-16毫秒的分辨率可能是一个问题(尽管不是我在这里介绍的特定情况下)Stopwatch.GetTimestamp()
可以回退到DateTime.Now.Ticks
当高性能时钟不可用时。我不确定这种情况会发生多久(是否有任何机器不再配备高性能时钟),但我确信,如果它使用Ticks,同样的问题也会发生Stopwatch.GetTimestamp()
将使用QueryPerformanceCounter()
API调用,从多个线程调用时可能会不稳定lastRxTime
时间戳的最佳方法是什么?我是否太担心环境中的低可能性问题。滴答声计数和Stopwatch.GetTimestamp()
functions?我对其他实现持开放态度,只要它们考虑到应用程序的多线程性质以及链接质量问题
更新7/17/2013(已部署解决方案!)
我已经部署了一个解决方案,希望让每个人都了解细节。一般来说,可能没有一个公认的答案,但在经历了这次经历后,我可以说,最初的解决方案肯定是一个问题。我将尽可能提供更多细节:
首先,NTP问题实际上是另一个问题的症状。出现问题的网络是AD域,两台服务器运行我的代码,设置为域控制器。事实证明,DCs是域的时间源。此外,还证明,这些系统上的系统时间在应用程序上从实时时钟漂移了一分钟大约11天,此时Windows正在纠正滑差。一旦Windows纠正了第一个DC上的滑差,第二个DC将同步他的时间,两个DC都会遇到上述问题
根据反馈和我最初的研究,我创建了一个测试程序,在断开连接期间运行,以记录DateTime.Now、Environment.TickCount和Stopwatch.GetTimestamp()的值。我发现在更正期间,Environment.TickCount和Stopwatch.GetTimestamp()都没有滑倒了,这意味着它们很适合用作DateTime.Now()的替代品。我选择了TickCount,因为它保证会出现在我所有部署的服务器上(而秒表可能会在一些我尚未找到的机器上退回到DateTime对象)。目前为止,它还没有出现问题。我在滚动问题上做了适当的努力,以防止出现问题,但需要等待我的系统运行那么长时间才能确定
我想指出的是,如果其他任何人遇到类似的问题,他们不应忽视使用下面列表中的任何其他解决方案。每个解决方案都有自己的merrit,事实上,对于大多数情况,简单计数器可能是最佳解决方案。我之所以没有使用此解决方案,是因为我在separ中有类似的代码ate严重依赖于紧张时间的区域。我无法处理16毫秒左右的滴答计数分辨率,但无法处理计数器解决方案引起的时间漂移(我在一个单独的产品中使用了这样的代码,最终漂移超过一秒一小时,使我超出了项目的规格)
再次感谢大家,如果有更多的问题出现,我一定会更新这个问题
我是否太担心Environment.TickCount和Stopwatch.GetTimestamp()函数中的低可能性问题
潜在的,
void OnReceiveComplete(IAsyncResult ar) {
...
mySocket.EndReceive(ar);
lastRxTime = DateTime.Now;
...
}
void CheckConnection() {
TimeSpan ts = DateTime.Now.Subtract(lastRxTime);
if(ts.TotalMilliseconds > timeout) {
Disconnect(string.Format("No packet received from the server for over {0} seconds.", timeout / 1000));
}
}
private int m_conTimer;
void OneSecondThreadCallback() {
if (++m_conTimer >= TIMEOUT_VALUE)
// Connection timed out. React accordingly.
}
// start the timer, callback in 10000 milliseconds, and don't fire more than once
var timer = new Timer(TimerCallback, null, 10000, Timeout.Infinite);
// to reset the timer when you receive data
timer.Change(10000, Timeout.Infinite);
// to stop the timer completely
timer.Change(Timeout.Infinite, Timeout.Infinite);
// and in your callback
private void TimerCallback(object state)
{
// disconnect, or do whatever you want
}
// to set up the timer
var timer = new Timer(10000) {AutoReset = false};
timer.Elapsed += TimerOnElapsed;
// to start the timer running
timer.Start();
// to reset the timer
timer.Stop();
timer.Start();
// and the callback
private void TimerOnElapsed(object sender, ElapsedEventArgs args)
{
// disconnect, or do whatever you want
}