SNTP 获取时间服务器UTC时间

来源:互联网 发布:淘宝直播间入口 编辑:程序博客网 时间:2024/05/17 02:23



// SntpTest.cpp : Defines the entry point for the console application.//#include "stdafx.h"#include <math.h>#include <time.h>#include <winsock2.h>#pragma comment(lib, "wsock32.lib")//ref : www.ietf.org/rfc/rfc2030.txt/*                   1                   2                   3    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|LI | VN  |Mode |    Stratum    |     Poll      |   Precision   |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|                          Root Delay                           |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|                       Root Dispersion                         |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|                     Reference Identifier                      |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|                                                               ||                   Reference Timestamp (64)                    ||                                                               |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|                                                               ||                   Originate Timestamp (64)                    ||                                                               |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|                                                               ||                    Receive Timestamp (64)                     ||                                                               |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|                                                               ||                    Transmit Timestamp (64)                    ||                                                               |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|                 Key Identifier (optional) (32)                |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|                                                               ||                                                               ||                 Message Digest (optional) (128)               ||                                                               ||                                                               |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+*/#pragma pack(push, 1)typedef struct _tagNTPTimestamp_t{  unsigned char Seconds[4]; //(32-bit unsigned fixed-point number. Big-endian)  unsigned char Seconds_Fraction[4]; //((32-bit unsigned fixed-point number. Big-endian) }NTPTIMESTAMP, *LPNTPTIMESTAMP;typedef struct _tagNTPMsgFmtV4_t{  struct   {    unsigned char LI:2; //Leap Indicator    //0  no warning    //1  last minute has 61 seconds    //2  last minute has 59 seconds)    //3  alarm condition (clock not synchronized)        unsigned char VN:3; //Version Number    //3  for Version 3 (IPv4 only)    //4  for Version 4 (IPv4, IPv6 and OSI)        unsigned char Mode:3; //indicating the mode    //0  reserved    //1  symmetric active    //2  symmetric passive    //3  client    //4  server    //5  broadcast    //6  reserved for NTP control message    //7  reserved for private use        unsigned char Stratum; //stratum level of the local clock    //0       unspecified or unavailable    //1       primary reference (e.g., radio clock)    //2-15    secondary reference (via NTP or SNTP)    //16-255  reserved        unsigned char Poll; //Poll Interval        unsigned char Precision; //Precision   };    unsigned char Root_Delay[4]; //Root Delay (32-bit signed fixed-point number. Big-endian)    unsigned char Root_Dispersion[4]; //Root Dispersion (32-bit unsigned fixed-point number. Big-endian)    char Reference_Identifier[4]; //Reference Identifier  //LOCL     uncalibrated local clock used as a primary reference for a subnet without external means of synchronization  //PPS      atomic clock or other pulse-per-second source individually calibrated to national standards  //ACTS     NIST dialup modem service  //USNO     USNO modem service  //PTB      PTB (Germany) modem service  //TDF      Allouis (France) Radio 164 kHz  //DCF      Mainflingen (Germany) Radio 77.5 kHz  //MSF      Rugby (UK) Radio 60 kHz  //WWV      Ft. Collins (US) Radio 2.5, 5, 10, 15, 20 MHz  //WWVB     Boulder (US) Radio 60 kHz  //WWVH     Kaui Hawaii (US) Radio 2.5, 5, 10, 15 MHz  //CHU      Ottawa (Canada) Radio 3330, 7335, 14670 kHz  //LORC     LORAN-C radionavigation system  //OMEG     OMEGA radionavigation system  //GPS      Global Positioning Service  //GOES     Geostationary Orbit Environment Satellite    NTPTIMESTAMP Reference_Timestamp; //Reference Timestamp (64-bit timestamp format. Big-endian)    NTPTIMESTAMP Originate_Timestamp; //Originate Timestamp (64-bit timestamp format. Big-endian)    NTPTIMESTAMP Receive_Timestamp; //ReceiveTimestamp (64-bit timestamp format. Big-endian)    NTPTIMESTAMP Transmit_Timestamp; //Transmit Timestamp (64-bit timestamp format. Big-endian)    //char Key_Identifier[4]; //Key Identifier (optional)    //unsigned char Message_Digest[16]; //Message Digest (optional)      }NTPMSGFMTV4, *LPNTPMSGFMTV4;#pragma pack(pop)//convert NTP timer to system timeBOOL _SNTPTimeToSystemTime(LPNTPTIMESTAMP pNTPTimeStame, SYSTEMTIME &tmDest){  // Verifies will fail if the needed buffer size is too large#define _MIN_DATE                (-657434L)  // about year 100#define _MAX_DATE                2958465L    // about year 9999    // Half a second, expressed in days#define _HALF_SECOND  (1.0/172800.0)  double dtSrc = 0;  double fMillsecods = 0;  //convert NTP time to days unit  {    u_long uSeconds = ntohl( *((u_long*)&pNTPTimeStame->Seconds[0]) ); //seconds    u_long uSecondsF = ntohl( *((u_long*)&pNTPTimeStame->Seconds_Fraction[0]) ); //Seconds Fraction        //convert Seconds Fraction to double type     double fSecondF = 0;    {      u_long uSecondF =uSecondsF;      int iLen = 0;      double fPart[64] = {0};              while(uSecondF && iLen < 64-1)      {        fPart[iLen++] = (uSecondF % 10);        uSecondF = uSecondF/10;      }            double fDiv = 10.0;      while((--iLen) >= 0)      {        fSecondF += fPart[iLen]/fDiv;        fDiv *= 10;      }    }            double vtDate = uSeconds;    if( pNTPTimeStame->Seconds[0] & 0x80 ) //since from 1900,January,1,00:00:00 to 2036    {    }    else //since form 6h 28m 16s UTC on 7 February 2036    {      vtDate += 0xFFFFFFFFU; //overflow    }    vtDate += (2 * 24 * 3600); //system time Dec. 30, 1899 to NTP Jan.1, 1900    dtSrc = vtDate  / (24 * 60 * 60); //convert to days    fMillsecods = (int)(fSecondF * 1000.0);  }  if (dtSrc > _MAX_DATE || dtSrc < _MIN_DATE) // about year 100 to about 9999return FALSE;  // The legal range does not actually span year 0 to 9999.  long nDays;             // Number of days since Dec. 30, 1899  long nDaysAbsolute;     // Number of days since 1/1/0  long nSecsInDay;        // Time in seconds since midnight  long nMinutesInDay;     // Minutes in day  long n400Years;         // Number of 400 year increments since 1/1/0  long n400Century;       // Century within 400 year block (0,1,2 or 3)  long n4Years;           // Number of 4 year increments since 1/1/0  long n4Day;             // Day within 4 year block  //  (0 is 1/1/yr1, 1460 is 12/31/yr4)  long n4Yr;              // Year within 4 year block (0,1,2 or 3)  BOOL bLeap4 = TRUE;     // TRUE if 4 year block includes leap year  double dblDate = dtSrc; // tempory serial date  // If a valid date, then this conversion should not overflow  nDays = (long)dblDate;  // Round to the second  dblDate += ((dtSrc > 0.0) ? _HALF_SECOND : -_HALF_SECOND);  nDaysAbsolute = (long)dblDate + 693959L; // Add days from 1/1/0 to 12/30/1899  dblDate = fabs(dblDate);  nSecsInDay = (long)((dblDate - floor(dblDate)) * 86400.);  // Calculate the day of week (sun=0, mon=1...)  tmDest.wDayOfWeek = (int)((nDaysAbsolute - 1) % 7L) + 0;  // Leap years every 4 yrs except centuries not multiples of 400.  n400Years = (long)(nDaysAbsolute / 146097L);  // Set nDaysAbsolute to day within 400-year block  nDaysAbsolute %= 146097L;  // -1 because first century has extra day  n400Century = (long)((nDaysAbsolute - 1) / 36524L);  // Non-leap century  if (n400Century != 0)  {    // Set nDaysAbsolute to day within century    nDaysAbsolute = (nDaysAbsolute - 1) % 36524L;        // +1 because 1st 4 year increment has 1460 days    n4Years = (long)((nDaysAbsolute + 1) / 1461L);    if (n4Years != 0)    {      n4Day = (long)((nDaysAbsolute + 1) % 1461L);    }    else    {      bLeap4 = FALSE;      n4Day = (long)nDaysAbsolute;    }  }  else  {    // Leap century - not special case!    n4Years = (long)(nDaysAbsolute / 1461L);    n4Day = (long)(nDaysAbsolute % 1461L);  }  if (bLeap4)  {    // -1 because first year has 366 days    n4Yr = (n4Day - 1) / 365;        if (n4Yr != 0)      n4Day = (n4Day - 1) % 365;  }  else  {    n4Yr = n4Day / 365;    n4Day %= 365;  }  // n4Day is now 0-based day of year. Save 1-based day of year, year number  int tm_yday = (int)n4Day + 1; /* days since January 1 - [0,365] */  tmDest.wYear = (WORD)(n400Years * 400 + n400Century * 100 + n4Years * 4 + n4Yr);  do   {      // Handle leap year: before, on, and after Feb. 29.    if (n4Yr == 0 && bLeap4)    {      // Leap Year      if (n4Day == 59)      {        /* Feb. 29 */        tmDest.wMonth = 2;        tmDest.wDay = 29;        break; //goto DoTime;      }            // Pretend it's not a leap year for month/day comp.      if (n4Day >= 60)        --n4Day;    }    // Make n4DaY a 1-based day of non-leap year and compute    //  month/day for everything but Feb. 29.    ++n4Day;    // Month number always >= n/32, so save some loop time */    // One-based array of days in year at month start    static int _MonthDays[13] =    {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365};    for (tmDest.wMonth = (n4Day >> 5) + 1;      n4Day > _MonthDays[tmDest.wMonth]; tmDest.wMonth++);    tmDest.wDay = (int)(n4Day - _MonthDays[tmDest.wMonth-1]);  }while(0);//DoTime:  if (nSecsInDay == 0)  {    tmDest.wHour = tmDest.wMinute = tmDest.wSecond = 0;  }  else  {    tmDest.wSecond = (WORD)(nSecsInDay % 60L);    nMinutesInDay = nSecsInDay / 60L;    tmDest.wMinute = (WORD)(nMinutesInDay % 60);    tmDest.wHour = (WORD)(nMinutesInDay / 60);  }  tmDest.wMilliseconds = (WORD)fMillsecods;  return TRUE;}int _SNTPGetUTCTime(const char *szSntpServer, SYSTEMTIME *ptmSys){    BOOL bRet = 0;  do  {    //init socket    int err = 0;    WSADATA wsa;    err = WSAStartup(MAKEWORD(2, 0), &wsa);    if(err != 0)    {      bRet = -1;      break;    }    SOCKET sSession = INVALID_SOCKET;    do     {      //get host ip by name      hostent * hp = gethostbyname(szSntpServer);      if(hp == NULL)      {        bRet = -2;        break;      }      sockaddr_in SvrIp;      SvrIp.sin_family= AF_INET;      memcpy(&SvrIp.sin_addr, hp->h_addr, sizeof(SvrIp.sin_addr));      SvrIp.sin_port= htons(123);            //create socket      sSession = socket(AF_INET, SOCK_DGRAM, 0);      if(sSession == INVALID_SOCKET)      {        bRet = -3;        break;      }      int iSizeSocketIn = sizeof(SOCKADDR_IN);      //sendto      int nTime = 3000;      setsockopt(sSession, SOL_SOCKET, SO_SNDTIMEO, (char *)&nTime, sizeof(nTime));             NTPMSGFMTV4 txMsg; memset(&txMsg, 0, sizeof(txMsg));      txMsg.LI = 3; //alarm condition (clock not synchronized)      txMsg.VN = 4; //4  for Version 4 (IPv4, IPv6 and OSI)      txMsg.Mode = 4; //4 server      if(SOCKET_ERROR == sendto(sSession, (const char*)&txMsg, sizeof(txMsg), 0, (sockaddr*)&SvrIp, iSizeSocketIn))      {        bRet = -4;        break;      }      //recvfrom      setsockopt(sSession, SOL_SOCKET, SO_RCVTIMEO, (char *)&nTime, sizeof(nTime));             NTPMSGFMTV4 rxMsg; memset(&rxMsg, 0, sizeof(rxMsg));      int nLenRcv = recvfrom(sSession, (char *)&rxMsg, sizeof(rxMsg), 0, (sockaddr*)&SvrIp, &iSizeSocketIn);      if(nLenRcv == SOCKET_ERROR)      {        bRet = -5;        break;      }      //use convert SNTP date to system time      SYSTEMTIME tmSys;      if(!_SNTPTimeToSystemTime(&rxMsg.Transmit_Timestamp, tmSys))      {        bRet = -6;        break;      }      if(ptmSys)      {        *ptmSys = tmSys;      }      bRet = 1;          }while(0);    //close socket    if(sSession != INVALID_SOCKET)    {      closesocket(sSession);      sSession = INVALID_SOCKET;    }        //WASClearup    WSACleanup();     }while(0);  return bRet;}int TestSNTP(){  LPCTSTR szTimeSvr[]=  {    "time.windows.com",    "time.nist.gov",    "time-nw.nist.gov",    "pool.ntp.org",    "europe.pool.ntp.org",    "asia.pool.ntp.org",    "oceania.pool.ntp.org",    "north-america.pool.ntp.org",    "south-america.pool.ntp.org",    "africa.pool.ntp.org",    "ca.pool.ntp.org",    "uk.pool.ntp.org",    "us.pool.ntp.org",    "au.pool.ntp.org",    0  };    for(size_t i = 0; szTimeSvr[i] ; ++i)  {    SYSTEMTIME tm = {0};    if(_SNTPGetUTCTime(szTimeSvr[i], &tm) > 0)    {      printf("%s: %04dY-%02dM-%02dD (Week %d) %02dH:%02dM:%02dS.%03dms\n",        szTimeSvr[i],        tm.wYear, tm.wMonth, tm.wDay, tm.wDayOfWeek,        tm.wHour, tm.wMinute, tm.wSecond, tm.wMilliseconds);    }  }  return 0;}int main(int argc, char* argv[]){  TestSNTP();  printf("Hello World!\n");  return 0;}

/* debug outputtime.windows.com: 2015Y-05M-25D (Week 1) 07H:05M:20S.915mstime.nist.gov: 2015Y-05M-25D (Week 1) 07H:05M:20S.133mspool.ntp.org: 2015Y-05M-25D (Week 1) 07H:05M:24S.573msoceania.pool.ntp.org: 2015Y-05M-25D (Week 1) 07H:05M:31S.116mssouth-america.pool.ntp.org: 2015Y-05M-25D (Week 1) 07H:05M:35S.617msafrica.pool.ntp.org: 2015Y-05M-25D (Week 1) 07H:05M:35S.235msca.pool.ntp.org: 2015Y-05M-25D (Week 1) 07H:05M:35S.405msuk.pool.ntp.org: 2015Y-05M-25D (Week 1) 07H:05M:36S.580msus.pool.ntp.org: 2015Y-05M-25D (Week 1) 07H:05M:36S.185msau.pool.ntp.org: 2015Y-05M-25D (Week 1) 07H:05M:36S.328msHello World!Press any key to continue*/










0 0
原创粉丝点击