您的位置:首页 > 理论基础 > 计算机网络

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

2012-02-05 22:03 337 查看
一、网络授时服务

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

Time Protocol (RFC-1305),DaytimeProtocol (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秒。也可到国家授时中心上去对时。但通常第一次打开这个网页时服务器时间和本地时间差别大些,多刷新几次又几乎一致了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: