獲取網絡時間


這兩天有一個應用須要獲取網絡時間。盡管一直知道能夠從時間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);
}

 
        



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM