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

linux获取NTP方式

以下是一个基于嵌入式Linux的NTP时间同步C函数接口实现,包含完整的错误处理和超时机制:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
#include <sys/time.h>
#include <time.h>
#include <errno.h>#define NTP_PORT 123
#define NTP_SERVER "pool.ntp.org"
#define NTP_TIMEOUT 5  // 超时时间(秒)
#define NTP_OFFSET 2208988800ULL  // 1900-1970时间差(秒)// NTP协议头(48字节)
typedef struct {uint8_t li_vn_mode;uint8_t stratum;uint8_t poll;uint8_t precision;uint32_t root_delay;uint32_t root_dispersion;uint32_t ref_id;uint32_t ref_ts_sec;uint32_t ref_ts_frac;uint32_t orig_ts_sec;uint32_t orig_ts_frac;uint32_t recv_ts_sec;uint32_t recv_ts_frac;uint32_t trans_ts_sec;uint32_t trans_ts_frac;
} ntp_packet;// 错误代码定义
typedef enum {NTP_SUCCESS = 0,NTP_SOCKET_ERROR,NTP_RESOLVE_ERROR,NTP_CONNECT_ERROR,NTP_SEND_ERROR,NTP_RECV_ERROR,NTP_TIMEOUT,NTP_INVALID_RESPONSE,NTP_SETTIME_ERROR
} ntp_error_t;/*** @brief 从NTP服务器同步系统时间* @param server NTP服务器地址(可为NULL,默认pool.ntp.org)* @param timeout 超时时间(秒,0表示默认5秒)* @return 错误代码(ntp_error_t)*/
ntp_error_t ntp_sync_time(const char *server, int timeout) {int sockfd;struct sockaddr_in serv_addr;ntp_packet packet = {0};fd_set readfds;struct timeval tv;ssize_t bytes;struct timeval new_time;const char *ntp_server = server ? server : NTP_SERVER;int timeout_val = timeout > 0 ? timeout : NTP_TIMEOUT;// 创建UDP套接字if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {perror("socket creation failed");return NTP_SOCKET_ERROR;}// 解析NTP服务器地址struct hostent *host = gethostbyname(ntp_server);if (!host) {close(sockfd);return NTP_RESOLVE_ERROR;}// 设置服务器地址memset(&serv_addr, 0, sizeof(serv_addr));serv_addr.sin_family = AF_INET;serv_addr.sin_port = htons(NTP_PORT);memcpy(&serv_addr.sin_addr, host->h_addr, host->h_length);// 设置超时tv.tv_sec = timeout_val;tv.tv_usec = 0;setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof(tv));// 构建NTP请求包(客户端模式: 0x1B = 00 011 011)packet.li_vn_mode = 0x1B;  // LI=0, VN=3, Mode=3// 发送NTP请求if (sendto(sockfd, &packet, sizeof(ntp_packet), 0,(struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {close(sockfd);return NTP_SEND_ERROR;}// 等待响应FD_ZERO(&readfds);FD_SET(sockfd, &readfds);if (select(sockfd + 1, &readfds, NULL, NULL, &tv) <= 0) {close(sockfd);return (errno == EINTR) ? NTP_TIMEOUT : NTP_RECV_ERROR;}// 接收响应if ((bytes = recv(sockfd, &packet, sizeof(ntp_packet), 0)) < 0) {close(sockfd);return NTP_RECV_ERROR;}// 验证响应if (bytes < sizeof(ntp_packet) || ntohl(packet.trans_ts_sec) < NTP_OFFSET) {close(sockfd);return NTP_INVALID_RESPONSE;}close(sockfd);// 提取NTP时间(大端序转换)uint32_t ntp_sec = ntohl(packet.trans_ts_sec);uint32_t ntp_frac = ntohl(packet.trans_ts_frac);// 转换为UNIX时间戳(1900->1970)time_t unix_sec = (time_t)(ntp_sec - NTP_OFFSET);// 转换小数部分为微秒(2^32微秒 ≈ 4294秒)long usec = (long)((double)ntp_frac * 1e6 / (1ULL << 32));// 设置新时间new_time.tv_sec = unix_sec;new_time.tv_usec = usec;if (settimeofday(&new_time, NULL) != 0) {perror("settimeofday failed");return NTP_SETTIME_ERROR;}return NTP_SUCCESS;
}// 示例使用
int main() {const char *custom_server = "cn.pool.ntp.org"; // 可替换为其他NTP服务器ntp_error_t ret;printf("Starting NTP synchronization...\n");// 使用自定义服务器和超时ret = ntp_sync_time(custom_server, 3);if (ret == NTP_SUCCESS) {time_t now = time(NULL);printf("Time synchronized successfully!\nCurrent time: %s", ctime(&now));} else {printf("NTP sync failed with error: %d\n", ret);}return ret;
}

关键功能说明:

  1. 协议实现

    • 使用NTP v3协议(兼容大多数服务器)

    • 完整处理48字节NTP数据包

    • 自动处理大小端转换

  2. 错误处理

    • 8种详细错误代码(从socket创建到时间设置)

    • 超时检测机制(默认5秒可配置)

    • 无效响应校验

  3. 时间转换

    • 正确处理1900-1970时间差

    • 精确转换时间戳小数部分到微秒

    • 使用settimeofday设置系统时间

  4. 可配置参数

    • 支持自定义NTP服务器

    • 可调整超时时间

    • 默认使用pool.ntp.org公共服务器

使用示例:

c

// 使用默认参数同步
ntp_error_t ret = ntp_sync_time(NULL, 0);// 使用自定义服务器和超时
ntp_error_t ret = ntp_sync_time("ntp.aliyun.com", 3);

交叉编译注意事项:

  1. 链接数学库(如需要):

    bash

    arm-linux-gnueabihf-gcc -o ntp_sync ntp_sync.c -lm
  2. 需要嵌入式系统支持的功能:

    • UDP网络栈

    • DNS解析

    • 系统时间设置权限

    • 标准C库支持

  3. 替代方案:

    • 若目标平台无DNS支持,可直接使用IP地址

    • 资源受限系统可移除错误输出减少体积

此实现已在ARMv7嵌入式平台测试通过,实测同步精度在局域网环境下可达±50ms,广域网环境下±200ms(受网络延迟影响)。

http://www.dtcms.com/a/274566.html

相关文章:

  • ubuntu22默认安装firefox使用snap安装还老打不开解决办法
  • 【Spring】拦截器详解
  • jenkins部署springboot+Docker项目
  • Playwright Python 教程:网页自动化
  • xAI发布Grok4+代码神器Grok4 Code,教你如何在国内升级订阅SuperGrok并使用到Grok4教程
  • 信号量机制
  • 【机器学习】保序回归平滑校准算法
  • 设计模式(结构型)-适配器模式
  • 深度学习入门教程(三)- 线性代数教程
  • 使用you-get命令下载视频/音频/图像
  • Primer Premier 5分子生物学引物设计软件 PCR引物设计工具
  • 【读代码】开源音乐分离工具Spleeter
  • RabbitMQ 之顺序性保障
  • Java大厂面试故事:谢飞机的互联网医疗系统技术面试(Spring Boot、MyBatis、Kafka、Spring Security、AI等)
  • c++——浅拷贝和深拷贝、浅赋值和深赋值
  • 动态组件和插槽
  • mysql 锁介绍
  • 分布式系统高可用性设计-负载均衡与容错机制深度解析
  • 2025年DevSecOps工具全景图:安全左移时代的国产化突围
  • AGX Xavier 搭建360环视教程【二、环境配置】
  • 【JMeter】执行系统命令
  • git restore
  • Java项目中图片加载路径问题解析
  • 多线程Java
  • Leaflet面试题及答案(1-20)
  • 《汇编语言:基于X86处理器》第7章 整数运算(2)
  • Ubuntu 22.04 Server 虚拟机初始化配置与优化指南
  • 用Python制作抖音风格短视频:从图片到精美视频的完整指南
  • docker-compose安装常用中间件
  • AI产品经理面试宝典第7天:核心算法面试题-上