首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> C++ 入門

C++ 通過 NTP 協議校正系統時間

     編輯:C++ 入門

利用 Winsock 連接 NTP 伺服器(如 time.windows.com:123 端口),接收 64 位時間戳(高 32 位秒數,低 32 位分數秒),轉換為 SYSTEMTIME 並調用 SetSystemTime 校正本地時鐘。需管理員權限。

核心流程

  1. WSAStartup 初始化 Winsock。
  2. 建立 UDP Socket (SOCK_DGRAM) 連接 NTP 伺服器 123 端口。
  3. 發送 NTP 請求封包(模式 3,版本 3,LI=0,Stratum=0 等,共 48 字節)。
  4. 接收回應,解析 Transmit Timestamp(偏移 40 字節)。
  5. NTP 時間起始於 1900-01-01,Windows FILETIME 起始於 1601-01-01,需換算:
    FILETIME = (NTP秒數 - 1900到1601的秒差) * 10^7。
  6. FileTimeToSystemTime → SetSystemTime。

關鍵代碼片段

#include <WinSock2.h>
#include <iostream>
#pragma comment(lib, "ws2_32.lib")

int main() {
    WSADATA wsa; WSAStartup(MAKEWORD(2,2), &wsa);
    SOCKET s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);

    sockaddr_in server; server.sin_family = AF_INET;
    server.sin_port = htons(123);
    server.sin_addr.s_addr = inet_addr("132.163.96.1"); // time-a.nist.gov

    // NTP 請求封包
    char pkt[48] = {0}; pkt[0] = 0x1B; // LI=0, VN=3, Mode=3
    sendto(s, pkt, 48, 0, (sockaddr*)&server, sizeof(server));

    // 接收回應
    recvfrom(s, pkt, 48, 0, NULL, NULL);
    ULONG ntpSecs = ntohl(*(ULONG*)(pkt + 40)); // Transmit Timestamp 秒部分

    // 轉換為 FILETIME
    const ULONGLONG SEC_1601_TO_1900 = 11644473600ULL; // 1601 到 1900 的秒數
    ULONGLONG ft = (ULONGLONG)(ntpSecs - SEC_1601_TO_1900) * 10000000ULL;
    FILETIME fileTime; *(ULONGLONG*)&fileTime = ft;

    SYSTEMTIME sysTime; FileTimeToSystemTime(&fileTime, &sysTime);
    SetSystemTime(&sysTime);
    std::cout << "Time synchronized." << std::endl;

    closesocket(s); WSACleanup(); return 0;
}

注意事項

  • 需管理員權限執行(SetSystemTime 需 SE_SYSTEMTIME_NAME 特權)。
  • 生產環境建議使用多個 NTP 伺服器並採用演算法(如 Marzullo)過濾異常值。
  • Windows 內建 w32time 服務已實現完整 NTP 客戶端,一般無需自行開發。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved