中国IT动力,最新最全的IT技术教程
最新100篇 | 推荐100篇 | 专题100篇 | 排行榜 | 搜索 | 在线API文档
首 页 | 程序开发 | 操作系统 | 软件应用 | 图形图象 | 网络应用 | 精文荟萃 | 教育认证 | 硬件维护 | 未整理篇 | 站长教程
ASP JS PHP工程 ASP.NET 网站建设 UML J2EESUN .NET VC VB VFP 网络维护 数据库 DB2 SQL2000 Oracle Mysql
服务器 Win2000 Office C DreamWeaver FireWorks Flash PhotoShop 上网宝典 CorelDraw 协议大全 网络安全 微软认证
硬件维护  CPU  主板  硬盘  内存  显卡  显示器  键盘鼠标  声卡音箱  打印机  机箱电源  BIOS  网卡  C#  Java  Delphi  vs.net2005
  当前位置:> 程序开发 > 编程语言 > Visual C++ > 网络与通信
利用RFC868协议编写网络对时程序
作者:未知 时间:2005-07-20 14:18 出处:VC知识库 责编:chinaitpower
              摘要:利用RFC868协议编写网络对时程序

利用RFC868协议编写网络对时程序


作者:四川绵阳电业局 缪元虎

下载源代码


一、网络授时服务

  网络授时服务是在网络上设置一些时间服务器,用户通过Internet访问这些时间服务器就可同步本地计算机时钟的服务。网络授时服务有三个协议,分别是Network Time Protocol (RFC-1305),Daytime Protocol (RFC-867),Time Protocol (RFC-868)。

有关这些协议的详细信息,可参考以下网站:

http://www.boulder.nist.gov/timefreq/service/its.htm
http://www.faqs.org/rfcs/rfc867.html
http://www.faqs.org/rfcs/rfc1305.html
http://www.faqs.org/rfcs/rfc868.html

我的程序中列出的时间服务器列表,主要来自:

http://www.boulder.nist.gov/timefreq/service/time-servers.html

更多的时间服务器列表请参考以下网站:

http://www.eecis.udel.edu/~mills/ntp/servers.html

二、Time Protocol (RFC-868)协议

  Time Protocol (RFC-868)协议是一种较简单的协议。此协议提供了一个独立于站点的,机器可读的日期和时间信息。时间服务返回的是以秒数,是从1900年1月1日午夜到现在的秒数。
  这个协议可以工作在TCP和UDP协议下。下面是通过TCP协议工作的时间协议的工作过程:这里S代表服务器,C代表客户。

S: 检测端口37
U: 连接到端口37
S: 以32位二进制数发送时间
U: 接收时间
U: 关闭连接
S: 关闭连接

如果服务器不能决定现在是什么时间,服务器会拒绝连接或不发送任何数据而直接关闭连接。

下面我们看看使用UDP协议的情况:这里S代表服务器,C代表客户。

S: 检测端口37
U: 发送一个空数据报到端口37
S: 接收这个空数据报
S: 发送包含32位二进制数(用于表示时间)的数据报
U: 接收时间数据报
如果服务器不能决定现在是什么时间,服务器会抛弃接收到的数据报而不作出任何应答。

三、网络对时的程序实现

  下面是使用TCP协议的实现网络对时的部分代码。GetRemoteTime 函数主要通过连接服务器szSever,并取得其回传的32位值:
BOOL GetRemoteTime(char* szSever, unsigned long& ulTime)
{
	SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0);	//使用UDP协议
	if(sock == INVALID_SOCKET)
	{
		return FALSE;
	}	
	sockaddr_in severAddr;
	severAddr.sin_family = AF_INET;
	severAddr.sin_port = htons(NET_TIME_PORT); 				
	severAddr.sin_addr.S_un.S_addr = inet_addr(szSever);

	if (sendto(sock, (char*)&ulTime, 4, 0, (sockaddr*)&severAddr, sizeof(severAddr)) == 4)
	{
		unsigned long flag = 1; 	
		if ((ioctlsocket(sock, FIONBIO, &flag) == 0))
		{	
			struct fd_set mask;			
			FD_ZERO(&mask);
			FD_SET(sock, &mask);
			
			struct timeval timeout;
			timeout.tv_sec = TIMEOUT_RECEIVE;
			timeout.tv_usec = 0;
			
			if (select(0, &mask, NULL, NULL, &timeout) == 1)
			{				
				if (recv(sock, (char*)&ulTime, 4, 0) == 4)
				{
					ulTime = ntohl(ulTime);
					closesocket(sock);
					return TRUE;
				}			
			}
		}
	}
	closesocket(sock);
	return FALSE;
}
      
MySetTime 函数的功能是将32位值转换为系统时间,并设置系统时间。
void MySetTime(unsigned long ulTime)
{
	FILETIME ft;
	SYSTEMTIME st;
	
	st.wYear = 1900;
	st.wMonth = 1;
	st.wDay = 1;
	st.wHour = 0;
	st.wMinute = 0;
	st.wSecond = 0;
	st.wMilliseconds = 0;
	
	SystemTimeToFileTime(&st, &ft);
	LARGE_INTEGER li = *(LARGE_INTEGER*)&ft;
	li.QuadPart += (LONGLONG)10000000 * ulTime;
	ft = *(FILETIME*)&li;
	FileTimeToSystemTime(&ft, &st);	
	SetSystemTime(&st);
}

int APIENTRY WinMain(HINSTANCE hInstance,
		 HINSTANCE hPrevInstance,
		 LPSTR     lpCmdLine,
		 int       nCmdShow)
{
	//初始化TCP协议
	WSADATA wsaData;	
	if(WSAStartup(MAKEWORD(2,2), &wsaData)!= 0)
	{
		MessageBox(NULL, "初始化网络协议失败!", "错误报告", MB_OK|MB_ICONHAND);
		return -1;
	}
	
	int i = 0;
	unsigned long ulTime = 0;
	
	while (sever[i] != NULL)
	{
		if (GetRemoteTime(sever[i], ulTime))
		{
			MySetTime(ulTime);
			char buff[100];
			sprintf(buff, "已成功与时间服务器\r\n%s\r\n的时间同步", sever[i]);
			MessageBox(NULL, buff, "成功报告", MB_OK|MB_ICONINFORMATION);
			return 0;
		}
		i++;
	}	
	MessageBox(NULL, "所有服务器均不能正常连接或超时!", "错误报告", MB_OK|MB_ICONHAND);
	WSACleanup();
	return 0;
}
      
至于使用UDP协议实现程序详见本文附带的代码。

四、结束语

  程序在VC6+WinXP下编写调试正确,并在Win98下运行正确。时间精度本人不敢妄下结论,但经与电视台对时,应小于1秒。也可到国家授时中心上去对时。但通常第一次打开这个网页时服务器时间和本地时间差别大些,多刷新几次又几乎一致了。
关闭本页
 
首页 | 投资与合作 | 服务条款 | 隐私政策 | 收藏本站 | 设为首页 | 新用户注册 | 免责声明 | 使用帮助
Copyright ©2005-2008 chinaitpower.com All rights reserved. www.chinaitpower.com 版权所有