SNTP 协议是用来同步本地的时间到 unix 时间戳. 通常嵌入式设备上电, 连接 AP
(access point
), 获取 IP
地址后, 就需要使用 SNTP
协议获取全球时间. 以便于下一步的应用交互和使用.
SNTP
工作原理比较简单, 通俗来说, 就是设备向 SNTP server
发送一包 SNTP
请求, 服务器收到请求后回复一包 SNTP reply
. 其中 SNTP reply
中就含有 unix 时间戳.
#include
#include
#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
握手失败.
ESP8266
上, 可以在 make menuconfig
-> Component config
-> LWIP
-> Enable lwip Debug
-> Enable debugging for SNTP
开启.
当然也可以把 UDP
, 甚至 IP
层的 debug
打开.
SNTP
协议请参考 SNTP RFC 文档.