当前位置: 首页 > news >正文

Linux:NTP服务

一、ping通外网

在开发板上使用NTP服务要确保 开发板能够ping外网!

ip addr show eth0          # 查看 eth0 是否有 IP 且 UP
ip route show              # 查看默认路由是否存在
ping 192.168.100.1         # 测试能否到达网关

ip route replace default via 192.168.100.1 dev eth0
replace 会自动替换已经存在的默认路由,非常方便。确保ip route show 有下面这个节点

同时确保Linux主机开启下面这个内容:

sudo sysctl -w net.ipv4.ip_forward=1
sudo iptables -t nat -A POSTROUTING -o enp2s0 -j MASQUERADE

之后板子就可以 ping 8.8.8.8ping www.baidu.com 了。

如果域名不通,再配置DNS /etc/resolv.conf

加一行:nameserver 223.5.5.5 nameserver 8.8.8.8

如果重启后 /etc/resolv.conf 被重置,需要在 启动脚本里重新写入 DNS,例如在 /etc/rc.local 或网络配置脚本里加:

echo -e "nameserver 223.5.5.5\nnameserver 8.8.8.8" > /etc/resolv.conf

我设置了开机自启动配置脚本,脚本如下(我还挂载了NFS,如果不需要可以关掉):

#!/bin/sh# 配置板子 IP
ip addr add 192.168.100.10/24 dev eth0 2>/dev/null# 挂载 NFS
mountpoint -q /mnt/driver_project || mount -t nfs -o vers=3,nolock 192.168.100.1:/home/dd/nfs_share /mnt/driver_project/# 设置默认路由
ip route replace default via 192.168.100.1 dev eth0# 更新 DNS
if ! grep -q "223.5.5.5" /etc/resolv.conf; thenecho -e "nameserver 223.5.5.5\nnameserver 8.8.8.8" >> /etc/resolv.conf
fiexit 0

把这个脚本放到RK3568的/etc/init.d下,做一个软连接到里面的文件,以S开头。

按照上面步骤即可ping通外网并且开机自启动。

过一段时间发现ping不通执行手动清除:

ip addr flush dev eth0
ip addr add 192.168.100.10/24 dev eth0
ip route replace default via 192.168.100.1 dev eth0 metric 100

二、lvgl下NTP服务代码

这里是有关NTP的socket网络编程,需要注意下面几个点:

1、ntp_server:NTP 服务器地址(如 ntp1.aliyun.com

2、NTP 使用 UDP 协议。SOCK_DGRAM + IPPROTO_UDP

3、NTP 默认端口是 123。

4、NTP 请求包固定 48 字节。

5、0x1b表示:00 011 011 00表示无警告 011表示NTPv3 011表示客户端模式。这是一个标准的 NTP 客户端请求包的起始字节。

6、NTP返回的时间戳在包的第 40~43 字节。

7、NTP 时间是从 1900-01-01 00:00:00 开始的秒数。

int sys_get_time_from_ntp(const char* ntp_server, int *year, int *month , int *day, int* hour, int *minute, int *second)
{struct addrinfo hints, *res = NULL;int sockfd = -1;memset(&hints , 0 , sizeof(hints));hints.ai_family = AF_UNSPEC;hints.ai_socktype = SOCK_DGRAM;hints.ai_protocol = IPPROTO_UDP; // 这里使用的是UDP/* 解析域名 */int gai_ret = getaddrinfo(ntp_server, "123", &hints, &res);if (gai_ret != 0) {fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(gai_ret));return -1;}/* 建立UDP socket */sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);if (sockfd == -1) {perror("socket creation failed");freeaddrinfo(res);return -1;}// NTP packetunsigned char buf[48] = {0};buf[0] = 0x1b;ssize_t sent = sendto(sockfd, buf, sizeof(buf), 0, res->ai_addr, res->ai_addrlen);if (sent != (ssize_t)sizeof(buf)) {perror("sendto");close(sockfd);freeaddrinfo(res);return -1;}// 使用 select 做监听,看看sockfd是否有返回数据fd_set readfds;FD_ZERO(&readfds);FD_SET(sockfd, &readfds);struct timeval timeout = {2, 0}; // 2sint ret = select(sockfd + 1, &readfds, NULL, NULL, &timeout);if (ret == 0) {fprintf(stderr, "receive from NTP server timeout\n");close(sockfd);freeaddrinfo(res);return -1;} else if (ret < 0) {perror("select error");close(sockfd);freeaddrinfo(res);return -1;}ssize_t rec = recvfrom(sockfd, buf, sizeof(buf), 0, NULL, NULL);if (rec < 0) {perror("recvfrom");close(sockfd);freeaddrinfo(res);return -1;} else if (rec < 48) {fprintf(stderr, "short ntp packet received\n");close(sockfd);freeaddrinfo(res);return -1;}close(sockfd);freeaddrinfo(res);uint32_t secsSince1900;memcpy(&secsSince1900, &buf[40], sizeof(secsSince1900));secsSince1900 = ntohl(secsSince1900); // 网络字节序转换为主机字节序。time_t unixTime = (time_t)(secsSince1900 - NTP_TIMESTAMP_DELTA);// set timezone to UTC+8setenv("TZ", "CST-8", 1);tzset();struct tm *timeinfo = localtime(&unixTime);if (!timeinfo) {perror("localtime failed");return -1;}if (year) *year = timeinfo->tm_year + 1900;if (month) *month = timeinfo->tm_mon + 1;if (day) *day = timeinfo->tm_mday;if (hour) *hour = timeinfo->tm_hour;if (minute) *minute = timeinfo->tm_min;if (second) *second = timeinfo->tm_sec;return 0;
}

主要的流程就是:建立UDP连接-->发送NTP请求包-->接收请求包-->解析请求包-->根据时区解析出正常的时间。

三、更新时间

void update_clock(lv_timer_t * timer)
{(void)timer;if (!time_label || !date_label) return;time_t current_time;struct tm *timeinfo;char time_str[64];char data_str[64];if (ntp_synced) {current_time = time(NULL);timeinfo = localtime(&current_time); // 这里的current_time时同步之后的时间} else {static struct tm default_time = {.tm_year = 100, // 2000.tm_mon = 0,.tm_mday = 1,.tm_hour = 0,.tm_min = 0,.tm_sec = 0};timeinfo = &default_time;}// 使用 snprintfsnprintf(time_str, sizeof(time_str), "%02d:%02d:%02d",timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec);snprintf(data_str, sizeof(data_str), "%04d-%02d-%02d",timeinfo->tm_year + 1900, timeinfo->tm_mon + 1, timeinfo->tm_mday);pthread_mutex_lock(&lvgl_mutex);lv_label_set_text(time_label, time_str);lv_label_set_text(date_label, data_str);pthread_mutex_unlock(&lvgl_mutex);
}

LVGL 本身不是线程安全的,要求所有 UI 的更新必须在同一个线程里执行,否则会出现:

  • 内存冲突(不同线程同时修改 LVGL 内部的数据结构)

  • 崩溃 / UI 显示异常

所以在在最后的时候修改值的文本信息加了一把锁。这样保证了:LVGL 内部的数据修改是原子化的,不会被并发打断

void set_time(lv_obj_t *cell){// 创建并保存全局 date_label/time_labeldate_label = lv_label_create(cell);lv_label_set_text(date_label, "----/--/--");lv_obj_align(date_label, LV_ALIGN_CENTER, 0, -14);lv_obj_set_style_text_color(date_label, lv_color_hex(0xFFFFFF), 0);lv_obj_set_style_text_font(date_label, &lv_font_montserrat_20, 0);time_label = lv_label_create(cell);lv_label_set_text(time_label, "--:--");lv_obj_align(time_label, LV_ALIGN_CENTER, 0, 14);lv_obj_set_style_text_color(time_label, lv_color_hex(0xFFFFFF), 0);lv_obj_set_style_text_font(time_label, &lv_font_montserrat_28, 0);int year, month, day, hour, minute, second;if (sys_get_time_from_ntp("ntp.aliyun.com", &year, &month, &day, &hour, &minute, &second) == 0){ntp_synced = true;printf("NTP 时间同步成功:%04d-%02d-%02d %02d:%02d:%02d\n",year, month, day, hour, minute, second);struct tm timeinfo = {.tm_year = year - 1900,.tm_mon = month - 1,.tm_mday = day,.tm_hour = hour,.tm_min = minute,.tm_sec = second};time_t new_time = mktime(&timeinfo);// 如果你想设置系统时间,可以在这里调用 settimeofday(需 root 权限)// struct timeval tv = { .tv_sec = new_time, .tv_usec = 0 };// settimeofday(&tv, NULL);} else {ntp_synced = false;printf("NTP 时间同步失败, 使用默认时间\n");}// 创建 LVGL 定时器,并立即更新一次lv_timer_t *timer = lv_timer_create(update_clock, 1000, NULL);// 将 user_data 设为 NULL,因为 update_clock 使用全局 date_label/time_labeltimer->user_data = time_label;   // v8.2 里直接赋值update_clock(timer);  
}

这样就实现了在lvgl中的时间同步!

四、计算周几

使用系统自带函数mktime来计算

int sys_get_day_of_week(int year , int month , int day)
{   struct tm timeinfo = {0};timeinfo.tm_year = year - 1900;timeinfo.tm_mon = month - 1;timeinfo.tm_mday = day;timeinfo.tm_hour = 12;/* 自动计算星期几 */mktime(&timeinfo);return timeinfo.tm_wday;
}

文章转载自:

http://VAT4zwKv.fyzyt.cn
http://KLAlFbFk.fyzyt.cn
http://HgDuCouO.fyzyt.cn
http://sSs7Gui3.fyzyt.cn
http://QV1rU0Nf.fyzyt.cn
http://VNgAOgiX.fyzyt.cn
http://YjcaBRI2.fyzyt.cn
http://3mJ2acRu.fyzyt.cn
http://nN0x4YpD.fyzyt.cn
http://mRbsGPx5.fyzyt.cn
http://DUqEdunf.fyzyt.cn
http://ZEhtabFY.fyzyt.cn
http://ws7ph9K2.fyzyt.cn
http://7DHdaHvl.fyzyt.cn
http://lpAyTECa.fyzyt.cn
http://feOsAAqo.fyzyt.cn
http://M6ZwBkr2.fyzyt.cn
http://WQEuMByk.fyzyt.cn
http://B3StpJX5.fyzyt.cn
http://aO2Eg3AK.fyzyt.cn
http://mPtH8MeN.fyzyt.cn
http://rLga4AxI.fyzyt.cn
http://HcqLLgrN.fyzyt.cn
http://ot8hNxTl.fyzyt.cn
http://65s1y72L.fyzyt.cn
http://S8MmspyU.fyzyt.cn
http://x9b9b7yq.fyzyt.cn
http://XfhnaOdQ.fyzyt.cn
http://rjb07NRV.fyzyt.cn
http://TqNwU8pi.fyzyt.cn
http://www.dtcms.com/a/371614.html

相关文章:

  • 【多模态学习】QA3:FFN的作用?Embedding生成方法的BERT和Word2Vec?非线性引入的作用?
  • Tomcat 日志文件名的命名规范
  • 基于单片机的可燃性气体泄漏智能报警系统
  • Ubuntu系统下Python连接国产KingbaseES数据库实现增删改查
  • 【linux kernel 常用数据结构和设计模式】【数据结构 2】【通过一个案例属性list、hlist、rbtree、xarray数据结构使用】
  • 论文阅读:DMD | Improved Distribution Matching Distillation for Fast Image Synthesis
  • 深入解析三色标记算法
  • Python struct模块 | 使用pack函数进行字节序打包
  • 二叉树的前中后序遍历(迭代法)
  • Camx-系统默认创建camxoverridesettings.txt
  • SQL面试题及详细答案150道(101-115) --- 数据操纵与定义篇
  • Adobe Premiere Pro(Pr)2022视频编辑软件安装教程与下载地址
  • 18.4 查看订单
  • 【考研C语言编程题】数组元素批量插入实现(含图示+三部曲拆解)
  • 九.弗洛伊德(Floyd)算法
  • pytorch非线性回归
  • Java 大视界 -- Java 大数据机器学习模型在金融市场风险评估与投资组合优化中的应用(407)
  • Python快速入门专业版(十一):布尔值与None:Python中的“真假”与“空值”(附逻辑判断案例)
  • 鸿蒙NEXT应用数据持久化全面解析:从用户首选项到分布式数据库
  • Linux笔记---封装套接字
  • 轻松Linux-8.动静态库的制作及原理
  • LeetCode 面试经典 150 题:移除元素(双指针思想优化解法详解)
  • 【TypeScript】闭包
  • 后端(fastAPI)学习笔记(CLASS 1):扩展基础
  • Spring Boot @RestController 注解详解
  • 腾讯云语音接口实现会议系统
  • ESP32与SUI-101A实现用电器识别
  • Wan2.2-S2V - 音频驱动图像生成电影级质量的数字人视频 ComfyUI工作流 支持50系显卡 一键整合包下载
  • 开始 ComfyUI 的 AI 绘图之旅-图生图(二)
  • VS2017安装Qt插件