這兩天有一個應用須要獲取網絡時間。盡管一直知道能夠從時間server獲取時間,卻從來也沒有操作過。借這個機會又一次進行一下深入了了解。
主要的思路就是:通過SOCKET連接時間server,直接接收從server發送的過來的時間數據。
void GetNetTime() { TIME_ZONE_INFORMATION tzinfo; DWORD dwStandardDaylight; int nRet; /* Initialize Winsock */ WORD wVersionRequested; WSADATA wsaData; int nErrCode; wVersionRequested = MAKEWORD(2, 2); nErrCode = WSAStartup(wVersionRequested, &wsaData); if (0 != nErrCode) { return; } /* Get server IP */ struct hostent *host; char *pServerIP; host = gethostbyname("time.nist.gov"); if (NULL == host) { return -1; } pServerIP = inet_ntoa(*(struct in_addr*)host->h_addr_list[0]); /* Connect to time server, and get time */ SOCKET sockfd; char cTimeBuf[40] = { 0 }; unsigned long ulTime = 0; int nTry = 0; do { if (5 == nTry++) { return -1; } sockfd = socket(AF_INET, SOCK_STREAM, 0); if (INVALID_SOCKET == sockfd) { continue; } int TimeOut = 3000;//設置接收超時6秒 setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&TimeOut, sizeof(TimeOut)); sockaddr_in addr; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(37); addr.sin_addr.s_addr = inet_addr(pServerIP); nRet = connect(sockfd, (sockaddr *)&addr, sizeof(addr)); if (SOCKET_ERROR == nRet) { continue; } nRet = recv(sockfd, (char *)&ulTime, sizeof(ulTime), 0); if ((SOCKET_ERROR != nRet) && (0 != nRet)) { break; } int nErr = WSAGetLastError(); TRACE(_T("[%d]%s"), nErr, ConvertErrcodeToString(nErr)); closesocket(sockfd); } while (1); closesocket(sockfd); unsigned long ulTimehl = ntohl(ulTime); ConvertTime(ulTimehl); }
void ConvertTime(unsigned long ulTime) { // Windows文件時間是一個64位的值,它是從1601年1月1日中午12:00到如今的時間間隔。 // 單位是1/10,000,000秒。即1000萬分之1秒(100-nanosecond) FILETIME ft; SYSTEMTIME st; // 首先將基准時間(1900年1月1日0點0分0秒0毫秒)轉化為Windows文件時間 st.wYear = 1900; st.wMonth = 1; st.wDay = 1; st.wHour = 0; st.wMinute = 0; st.wSecond = 0; st.wMilliseconds = 0; SystemTimeToFileTime(&st, &ft); // 然后將Time Protocol使用的基准時間加上逝去的時間(ulTime) LONGLONG *pLLong = (LONGLONG *)&ft; /* 注意: 文件時間單位是1/1000 0000秒(即100ns)。 須要將從時間server上獲取的以秒為單位的ulTime做一下轉換 */ *pLLong += (LONGLONG) 10000000 * ulTime; // 再將時間轉化回來。更新系統時間 FileTimeToSystemTime(&ft, &st); TRACE(_T("%04d%02d%02d %02d:%02d:%02d\n"), st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond ); return; }
各地時差都不一致,能夠依據GetTimeDiff函數計算當地時差,對上面的時間加以調整:
void GetTimeDiff() { float bias; long sminute,shour; /* 獲取時區信息 */ dwStandardDaylight = GetTimeZoneInformation(&tzinfo); //獲取時區與UTC的時間差 應該返回-8 if (dwStandardDaylight == TIME_ZONE_ID_INVALID) //函數運行失敗 { return; } /* 時差調整 */ bias = tzinfo.Bias; if (dwStandardDaylight == TIME_ZONE_ID_STANDARD) //標准時間有效 bias += tzinfo.StandardBias; if (dwStandardDaylight == TIME_ZONE_ID_DAYLIGHT) //夏令時間 bias += tzinfo.DaylightBias; shour = bias / 60; sminute = fmod(bias, (float)60); }