hATEmATH的网上田园

喂马 劈柴 做一个幸福的人
<2008年12月>
30123456
78910111213
14151617181920
21222324252627
28293031123
45678910
公告
  • ◇ 欢迎来到这里的每一位朋友。

    ◇ 无需注册即可评论或留言。

    ◇ 文章无"转载(ZT)"字样均为原创。

    ◇ "随笔分类"中包含我的所有随笔

留言簿(13)

随笔分类

随笔档案

文章分类

文章档案

相册

工具网站

搜索

最新评论

阅读排行榜

评论排行榜

 
VC知识库BLOG   首页  新随笔  联系  聚合  登录 
  随笔-127 文章-20 评论-454 Trackbacks-0


VC++中实现同步Internet时间

HateMath2005@163.com

关键词Internet时间 同步时间 校时

 

转载请注明原创出处:HateMath的网上田园(http://blog.vckbase.com/hatemath/

写作目的:(此段可跳过)
    同步Internet时间,即通过Internet的校时网站传来的数据校准本机时间。但是现在网络上查到的相关编程资料并不多,且其中多是VB和Delphi的代码,VC的代码我还没找到过。是这个东西太难了?应该不是;是太简单了?那也总该有人写吧。
   我认为,自己懂和让别人懂压根不是一回事,我写这篇文章,目的当然是后者。当然,理工科出身的河蚌不大可能像文科出身的河蚌那样修出光彩夺目的珍珠来,所以,行文有不妥之处,欢迎指正。

校时原理:
        互联网上有很多时间服务器能够提供准确的时间,我们通过连接到这样的服务器来获取时间值。这里向大家介绍一下服务器传来的数据格式先。数据一共四个字节(4 Byte),我们可以在接收数据后对它进行“重新组装”,把组装所得的值放在一个32位的整数里,这个值的意义是:自190011000 服务器发送这个时间数据时 所经历的秒数。显然,任何一个时刻到1900年所经历的秒数是唯一的,因此,由服务器传来的时间数据即可推出现在的时间,然后用API函数调整系统的时间即可。


流程图如下:


设计目标:

        好了,我们的目标是:(没有蛀牙~)
    -_-!!
    常言说一图千言,我们还是看图吧:

 

 

 

程序的实现:

从技术角度来看,解决三个问题即可:
1. 通过网络通信从服务器获取时间数据。
2. 处理基于1900年的时间数据,转化为我们常见的时间形式。
3. 解决网络造成的延时问题。

下面分条讲述:

1.
通过网络通信从服务器获取时间数据。

至于接收数据,没什么可说的,这里用CSocket就可以了。

 

代码片断:

    CSocket sockClient;
    sockClient.Create();            
//创建socket

    
//for debug
    m_info += "Connect server: " + strServer + " ";
    UpdateData(FALSE);
    
//for debug

    sockClient.Connect((LPCTSTR)strServer, 
37); // strServer:时间服务器网址; 37:端口号

    DWORD dwTime 
= 0;                //用来存放服务器传来的标准时间数据
    unsigned char nTime[8];            //临时接收数据
    memset(nTime, 0sizeof(nTime));

    sockClient.Receive(nTime, 
sizeof(nTime));    //接收服务器发送来得4个字节的数据
    sockClient.Close();                //关闭socket
    
    
//for debug
    m_info += "Connect shut down. ";
    UpdateData(FALSE);
    
//for debug

    dwTime 
+= nTime[0<< 24;        //整合数据    
    dwTime += nTime[1<< 16;
    dwTime 
+= nTime[2<< 8;
    dwTime 
+= nTime[3];        

    
if(0 == dwTime)    return FALSE;


 

到此为止,服务器传来的时间数据经过“重新组装”已经正确放置到DWORD类型的变量 dwTime 里面了。下面我们接着对其进行必要的处理。


2.
处理基于1900年的时间数据,转化为我们常见的时间形式。

在前面我们提到,时间数据已经正确放置到变量 dwTime 里面了。那么,怎样由它得到现在的时间呢?

微软已经给我们提供了一个很好用的时间类:CTime。不过,MFCCTime类的时间起点是基于1970年的,而dwTime 里面的秒数是从1900年计时的

CTime?无法由 dwTime 中的数据直接构造CTime类的对象。

C的函数库?我尝试了多次,N次碰壁。

现场采访:这个时候,换了你,你会怎么办?                    

众人:◎#¥%#%……※……×※◎^&*(^*                     

错!应该去人气超强的VCKbase论坛!欢迎访问:www.vckbase.com/bbs

 

没错,我就是在论坛上经过讨论找到答案的。说起最终敲定的实现方法,其实很简单- 改变计时基准。


时间转换的方法如下:

 

1.  用 COleDateTime 和 COleDateTimeSpan 算出190011000 197011000 所经历的秒数 dwSec00to70

2.  dwTime 中减去 dwSec00to70。此后,dwTime 所代表的就是自197011000秒以来逝去的秒数――显然,dwTime 已经被我们转变为基于1970年的时间值了,这回可以用CTime进行处理了。

 怎么样?不复杂吧。(想起了近几天屡试屡败的经历和查阅的N多资料,自己吐血先)

代码片断:

    //服务器传来的数据是自从1900年以来的秒数
    
//取得 1900~1970 的时间差(以秒数计算) ,放在dwSpan里面
    COleDateTime t00( 190011000 ); // 1900.1.1 00:00:00 
    COleDateTime t70( 197011000 ); // 1970.1.1 00:00:00 

    COleDateTimeSpan ts70to00 
= t70 - t00; 
    DWORD dwSpan 
= (DWORD)ts70to00.GetTotalSeconds(); 
    ASSERT( dwSpan 
== 2208988800L ); 
    
    
//把时间变为基于1970年的,便于用CTime处理
    dwTime -= dwSpan;        
    
//考虑网络延迟因素
    dwTime += dwDely;
    
//构造当前时间的CTime对象
    CTime timeNow = (CTime)dwTime;

    
//for debug
    m_info += timeNow.Format("%Y.%m.%d  %H:%M:%S  ");
    UpdateData(FALSE);
    
//for debug



3. 解决网络造成的延时问题。

    在从服务器获取时间数据时,由于网络本身的不稳定性,一般会有时间上的延迟(几秒以内),这样一来,从服务器接收到的数据总早于的真实时间。解决的办法是设定一个计时器,计算出本机从开始网络连接到接收完数据所耗费的时间dwDelay,然后加到 dwTime 上进行补偿。这样一来误差就可以控制在1秒以内(如果你不用你的爱机控制导弹飞行或者航天发射,应该够用了),详见源码。


  
演示程序及代码下载地址:
http://blog.vckbase.com/Files/HateMath/SyncTime.rar

正文结束。

/*-----------------------------------
写后感:
1.对VCKbase论坛的网友的热忱帮助表示谢意。
2.关于时间基准的转换问题,如果还有新的办法,欢迎指教。
3.如果这篇文章稍加改动后给本站的在线杂志投稿,各位觉得发表的可能有多大?:-)
------------------------------------*/

posted on 2005-10-12 10:49 HateMath的网上田园 阅读(4620) 评论(8)  编辑 收藏
Comments
  • # re: 在VC++中实现同步Internet时间
    zuilang
    Posted @ 2005-10-12 11:23
    完全可以发表:)稿费有吗?
  • # re: 在VC++中实现同步Internet时间
    bborn
    Posted @ 2005-10-12 22:39
    c++的代码很早就有了
    http://www.codeproject.com/internet/csntp.asp
    原来我就用这个类在98下写过一个校时程序

    还有 看了你的那个xp下vc校时的代码
    如果只是纯粹的校时的话
    这样更方便
    http://bborn.cn/blog/article.asp?id=46
  • # re: 在VC++中实现同步Internet时间
    周星星
    Posted @ 2005-10-13 08:34
    "整合数据"为什么不用ntohl?这样就平台无关了。
  • # re: 在VC++中实现同步Internet时间
    周星星
    Posted @ 2005-10-13 08:45
    你使用的VC++6.0打补丁VSSP6了没有,因为我发现debug目录中的synctime.exe在我这儿运行异常。
  • # re: 在VC++中实现同步Internet时间
    HateMath的网上田园
    Posted @ 2005-10-13 18:33
    to 星星 :
    1)thanks,那样确实更方便.我的代码可以认为是给了另一种方法吧.
    用ntohl涵数时,代码改为:
    ....
    DWORD dwTime = 0; //用来存放服务器传来的标准时间数据
    sockClient.Receive(&dwTime, sizeof(dwTime)); //接收服务器发送来得4个字节的数据
    dwTime = ntohl(dwTime);
    if(0 == dwTime) return FALSE;
    ....

    2)我也不知道打了SP6没有,我当时用的别人的机子......
    不知道怎样才能看到打了没有呢?
  • # re: 在VC++中实现同步Internet时间

    Posted @ 2006-11-14 15:31
    写得不错,加油了。哈哈
  • # re: 在VC++中实现同步Internet时间
    小瑞
    Posted @ 2007-05-20 13:51
    呵呵,非常感谢楼主,从楼主的文章中学到很多,嘿嘿,看完后有个问题想请教下,要想在窗口中同时显示本机时间和实时输出服务器的时间该怎么办呢?
    呵呵,再次表示感谢^-^
  • # re: 在VC++中实现同步Internet时间
    HateMath的网上田园
    Posted @ 2007-06-06 18:51
    to 小瑞:
    完整意义上的实时输出服务器的时间恐怕有些困难,处于网络的限制你不可能更新的那么快的,除非用些小技巧。
标题  
姓名  
主页
验证码 *
内容   
  登录  使用高级评论  Top
[使用Ctrl+Enter键可以直接提交]