1 //*******************************************************************
2 //Time Protocol是一种非常简单的应用层协议。它返回一个未格式化的32位二进制数字,
3 //这个数字描述了从1900年1月1日午夜到现在的秒数。服务器在端口37监听协议请求,以
4 //TCP/IP或者UDP/IP格式返回响应。将服务器的返回值转化为本地时间是客户端程序的责任。
5 //这里使用的时间服务器是129.132.2.21,更多的服务器地址在“http://tf.nist.gov/service/time-servers.html
6 //网站列出。
7 //*******************************************************************
8
9 #include <iostream>
10 #include <WinSock2.h>
11
12 using namespace std;
13
14 #pragma comment(lib, "ws2_32")
15
16 void SetTimeFromTP(ULONG ulTime)
17 {
18 //Windows文件时间是一个64位的值,它是从1601年1月1日中午12:00到现在的时间间隔,
19 //单位是1/1000 0000秒,即1000万分之1秒
20 FILETIME ft;
21 SYSTEMTIME st;
22
23 st.wYear = 1900;
24 st.wMonth = 1;
25 st.wDay = 1;
26 st.wHour = 0;
27 st.wMinute = 0;
28 st.wSecond = 0;
29 st.wMilliseconds = 0;
30
31 SystemTimeToFileTime(&st, &ft);
32 //然后将Time Protocol使用的基准时间加上已经逝去的时间,即ulTime
33 LONGLONG *pllLong = (PLONGLONG)&ft;
34 //注意文件时间单位是1/1000 0000秒,即1000万分之1秒
35 *pllLong += (LONGLONG)10000000 * ulTime;
36 //再将时间转化回来,更新系统时间
37 FileTimeToSystemTime(&ft, &st);
38 SetSystemTime(&st);
39 }
40
41 int main(int argc, char **argv)
42 {
43 WSADATA wsaData;
44 WSAStartup(WINSOCK_VERSION, &wsaData);
45
46 SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
47 if (INVALID_SOCKET == s)
48 {
49 cout << "socket error : " << GetLastError() << endl;
50 return 0;
51 }
52
53 SOCKADDR_IN servAddr;
54 servAddr.sin_family = AF_INET;
55 servAddr.sin_port = htons(37);
56 servAddr.sin_addr.S_un.S_addr = inet_addr("129.132.2.21");
57
58 if (-1 == connect(s, (PSOCKADDR)&servAddr, sizeof(servAddr)))
59 {
60 cout << "connect error : " << WSAGetLastError() << endl;
61 return 0;
62 }
63
64 //等待接收时间协议返回,最好使用异步IO,以便设置超时
65 ULONG ulTime = 0;
66 int iRecv = recv(s, (char*)&ulTime, sizeof(ulTime), 0);
67 if (iRecv > 0)
68 {
69 ulTime = ntohl(ulTime);
70 SetTimeFromTP(ulTime);
71 cout << "成功与服务器时间同步!" << endl;
72 }
73 else
74 {
75 cout << "时间服务器不能确定当前时间!" << endl;
76 }
77
78 shutdown(s, SD_RECEIVE);
79 closesocket(s);
80
81 WSACleanup();
82 return 0;
83 }