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

RFC 868 協定實作網路校時程式:TCP/UDP 雙模式、系統時間同步完整教學

     編輯:關於VC++

前言

網路校時服務讓電腦自動同步標準時間。RFC 868 (Time Protocol) 是最簡單的協定:伺服器監聽 Port 37,回傳自 1900-01-01 00:00:00 UTC 至今的秒數 (32-bit 無號整數)。本文示範 VC++ 實作 TCP/UDP 雙模式客戶端,含系統時間設定、多伺服器輪詢容錯。

RFC 868 協定流程

TCP 模式

  1. 客戶連接伺服器 Port 37。
  2. 伺服器送出 4 位元組巨集序 (Big-Endian) 秒數。
  3. 客戶接收後關閉連線。

UDP 模式

  1. 客戶送出空封包至伺服器 Port 37。
  2. 伺服器回傳 4 位元組秒數。
  3. 無連線狀態,若伺服器無法取得時間則直接丟棄不回應。

核心程式碼實作

1. 取得遠端時間 (UDP 範例)


BOOL GetRemoteTime(char* szServer, unsigned long& ulTime) {
    SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0); // UDP
    if (sock == INVALID_SOCKET) return FALSE;

    sockaddr_in addr; addr.sin_family = AF_INET;
    addr.sin_port = htons(37); // RFC 868 Port
    addr.sin_addr.s_addr = inet_addr(szServer);

    unsigned long dummy = 0;
    // 送出空封包 (4 bytes)
    if (sendto(sock, (char*)&dummy, 4, 0, (sockaddr*)&addr, sizeof(addr)) != 4) {
        closesocket(sock); return FALSE;
    }

    // 非阻塞等待回應 (Timeout 3 秒)
    unsigned long flag = 1;
    ioctlsocket(sock, FIONBIO, &flag);
    fd_set fds; FD_ZERO(&fds); FD_SET(sock, &fds);
    timeval tv = {3, 0};
    if (select(0, &fds, NULL, NULL, &tv) == 1) {
        if (recv(sock, (char*)&ulTime, 4, 0) == 4) {
            ulTime = ntohl(ulTime); // 網路序轉主機序
            closesocket(sock); return TRUE;
        }
    }
    closesocket(sock); return FALSE;
}

2. 秒數轉 SYSTEMTIME 並設定系統時間


void MySetTime(unsigned long ulTime) {
    FILETIME ft; SYSTEMTIME st;
    // 基準時間 1900-01-01
    st.wYear = 1900; st.wMonth = 1; st.wDay = 1;
    st.wHour = st.wMinute = st.wSecond = st.wMilliseconds = 0;
    SystemTimeToFileTime(&st, &ft);

    LARGE_INTEGER li = *(LARGE_INTEGER*)&ft;
    li.QuadPart += (LONGLONG)10000000 * ulTime; // 1 秒 = 10^7 100ns
    ft = *(FILETIME*)&li;
    FileTimeToSystemTime(&ft, &st);
    SetSystemTime(&st); // 需 SE_SYSTEMTIME_NAME 權限
}

3. 主程式:多伺服器輪詢


char* servers[] = {
    "time.nist.gov", "time-a.nist.gov", "time-b.nist.gov",
    "ntp1.aliyun.com", "cn.pool.ntp.org", NULL
};

int APIENTRY WinMain(HINSTANCE hInst, HINSTANCE, LPSTR, int) {
    WSADATA wsa; WSAStartup(MAKEWORD(2,2), &wsa);

    for (int i=0; servers[i]; i++) {
        unsigned long t;
        if (GetRemoteTime(servers[i], t)) {
            MySetTime(t);
            char msg[200];
            wsprintf(msg, "已與 %s 同步成功", servers[i]);
            MessageBox(NULL, msg, "成功", MB_OK|MB_ICONINFORMATION);
            WSACleanup(); return 0;
        }
    }
    MessageBox(NULL, "所有伺服器連線失敗或逾時", "錯誤", MB_OK|MB_ICONHAND);
    WSACleanup(); return -1;
}

TCP 模式差異

  • socket(AF_INET, SOCK_STREAM, 0)
  • connect() 後直接 recv(sock, &ulTime, 4, 0),無需送出空封包。
  • 其餘流程 (ntohl、MySetTime) 相同。

權限與相容性

  • SetSystemTime 需要「變更系統時間」權限 (Administrators/Power Users 或透過群組原則授予)。
  • Win9x/NT/2000/XP/Win7+ 均可執行。
  • 精度:網路延遲通常 <1 秒,配合多伺服器輪詢可達亞秒級。

常見公共時間伺服器

  • NIST: time.nist.gov, time-a.nist.gov, time-b.nist.gov
  • 台灣: tick.stdtime.gov.tw (國家標準時間實驗室)
  • 中國大陸: ntp1.aliyun.com, cn.pool.ntp.org
  • 全球: pool.ntp.org (NTP 協定,非 RFC 868)

總結

RFC 868 協定簡單易實作,適合嵌入式裝置或輕量級應用快速同步時間。本文提供完整 TCP/UDP 雙模式 VC++ 範例,含錯誤處理、多伺服器容錯、系統時間設定,可直接整合至專案中。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved