簡介
SNTP 協議是用來同步本地的時間到 unix 時間戳. 通常嵌入式設備上電, 連接 AP
(access point
), 獲取 IP
地址後, 就需要使用 SNTP
協議獲取全球時間. 以便於下一步的應用交互和使用.
SNTP
工作原理比較簡單, 通俗來說, 就是設備向 SNTP server
發送一包 SNTP
請求, 服務器收到請求後回覆一包 SNTP reply
. 其中 SNTP reply
中就含有 unix 時間戳.
參考代碼
#include <stdio.h>
#include <time.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "lwip/apps/sntp.h"
#include "esp_log.h"
static const char *TAG = "sntp";
static void esp_initialize_sntp(void)
{
ESP_LOGI(TAG, "Initializing SNTP");
sntp_setoperatingmode(SNTP_OPMODE_POLL);
sntp_setservername(0, "ntp1.aliyun.com");
sntp_init();
}
void esp_wait_sntp_sync(void)
{
char strftime_buf[64];
esp_initialize_sntp();
// wait for time to be set
time_t now = 0;
struct tm timeinfo = { 0 };
int retry = 0;
while (timeinfo.tm_year < (2019 - 1900)) {
ESP_LOGD(TAG, "Waiting for system time to be set... (%d)", ++retry);
vTaskDelay(100 / portTICK_PERIOD_MS);
time(&now);
localtime_r(&now, &timeinfo);
}
// set timezone to China Standard Time
setenv("TZ", "CST-8", 1);
tzset();
strftime(strftime_buf, sizeof(strftime_buf), "%c", &timeinfo);
ESP_LOGI(TAG, "The current date/time in Shanghai is: %s", strftime_buf);
}
// 應用層直接調用 esp_wait_sntp_sync() 即可.
使用說明
A). 代碼中 SNTP APIs
說明請參考 lwip 官方文檔.
B). sntp_setservername
除了可以設置域名, 也可以設置 IP
地址, 例如 sntp_setservername(0, "120.25.115.20");
C). 如果有必要, 請多設置幾個 SNTP server
, 防止某個 SNTP server
暫時關閉服務而導致產品部分功能無法使用, 例如:
sntp_setservername(0, "ntp1.aliyun.com");
sntp_setservername(1, "210.72.145.44"); // 國家授時中心服務器 IP 地址
sntp_setservername(2, "1.cn.pool.ntp.org");
說明:
默認情況下,ESP8266/ESP32
只允許開啓一個SNTP server
(節省資源考慮), 如果用戶需開啓多個SNTP server
, 請配置:
ESP8266
請在 make menuconfig -> Component config -> LWIP -> DHCP -> Maximum bumber of NTP servers 修改爲 3ESP32
請在 make menuconfig -> Component config -> LWIP -> SNTP -> Maximum bumber of NTP servers 修改爲 3
D). 配置多個 SNTP server
時, 不是同時發送多個 SNTP
請求報文, 而是輪循方式. 第一個處理超時後, 進行和第二個 SNTP server
交互, 這樣依次進行到最後一個, 最後一個處理超時後, 會再和第一個 SNTP server
交互.
E). 最好不在任何 callback
或中斷處理函數中調用 esp_wait_sntp_sync()
, callback
/中斷中, 調用任何阻塞的 API
, 理論上都有死鎖的可能.
F). 任何有校驗服務器證書的 TLS
過程 (本地有 CA
證書), 請務必開啓 SNTP
功能, 否則會因爲校驗服務器證書有效期失敗而導致 TLS
握手失敗.
SNTP 調試
ESP8266
上, 可以在 make menuconfig
-> Component config
-> LWIP
-> Enable lwip Debug
-> Enable debugging for SNTP
開啓.
當然也可以把 UDP
, 甚至 IP
層的 debug
打開.
SNTP 交互抓包展示
SNTP 請求報文:
SNTP 回覆報文:
SNTP
協議請參考 SNTP RFC 文檔.