一、什么是网络时间协议
网络时间协议(Network Time Protocol, 简称NTP) 是一种用来同步计算机时钟的协议。 它设计用来解决电脑时钟问题,确保计算机和其他设备的时间是一致的,并尽可能减小同步时间的误差,从而达到精准的时间同步。
二、LinuxPTP框架介绍
LinuxPTP是一个基于linux内核的高效的网络时间协议实现,它实现了IEEE1588-2008协议。相比传统的NTP来说,其精度更高(可以达到1~10纳秒级别),并且支持同时进行多路同步,可以适用于各种高精度时钟同步场景,如自动化生产线、数据中心等。
LinuxPTP的主要架构分为核心层、协议守护进程(daemon)层、系统调用库(libc)层和用户空间应用程序层。核心层提供了基本的时间戳服务和基于系统计时器的帧处理过程,daemon层负责协议状态机的实现,libc层为用户空间应用提供了与内核交互的接口。用户空间应用程序层提供命令行工具和API等服务。
三、使用LinuxPTP进行时间同步
使用LinuxPTP进行时间同步分为两个步骤:
1. 配置网卡为PTP模式
#ip link set eno0 multicast on
#ip link set eno0 type ptp
这样就把eno0网卡配置成了PTP模式。
2. 启动ptp4l守护进程并绑定所需要同步的网卡:
#ptp4l -i eno0 -m -H -A -S
其中-i指定绑定的网卡;-m表示使用多播传输模式;-H表示以硬件时钟为时间源;-A表示使用全自适应时钟滤波器;-S表示使用对称模式进行同步。
四、示例代码
以下是一个使用LinuxPTP进行时间同步的示例代码:
#include
#include
#include
#include
#include
#include
#include
#include
#define TX_TYPES PTP_TX_TYPE_SYNC | PTP_TX_TYPE_DELAY_REQ //同步和延迟请求
#define RX_TYPES PTP_RX_TYPE_SYNC //只接收同步包
int main(int argc, char *argv[]) {
/* 初始化结构体 */
int clockid, ret;
struct ptp_clock_caps caps; //设备属性
struct ptp_clock_time tx_time, rx_time;
struct ptp_clock_retval tsret;
struct timespec timeout; //超时
struct sockaddr_in addr, from;
socklen_t addr_len = sizeof(struct sockaddr_in);
char buf[300];
/* 打开时钟设备 */
clockid = ptp_clock_open(0);
if (clockid < 0) {
printf("Unable open ptp clock\n");
exit(1);
}
/* 获取设备属性 */
ret = ptp_clock_getcaphash(clockid, &caps);
if (ret < 0) {
printf("Unable retrieve clock capabilities from the PTP clock\n");
exit(1);
}
/* 打开udp套接字 */
int sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sockfd < 0) {
printf("Unable to create socket\n");
exit(1);
}
memset(&addr, 0, sizeof(struct sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_port = htons(319);
addr.sin_addr.s_addr = htonl(INADDR_ANY); /* 接收所有网卡上面的时钟包 */
/* 绑定地址 */
if (bind(sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < 0) {
printf("Unable to bind socket\n");\
close(sockfd);
exit(1);
}
/* 接收PTP包 */
while (1) {
timeout.tv_sec = 5;
timeout.tv_nsec = 0;
memcpy(&from, &addr, sizeof(struct sockaddr_in));
memset(&buf, 0, sizeof(buf));
ret = ptp_clock_get_rxts(clockid, &from, &rx_time, &tsret);
if (ret < 0) {
printf("Unable receive PTP packet\n");
continue;
}
printf("Received PTP packet\n");
ret = ptp_clock_gettime(clockid, &tx_time);
if (ret < 0) {
printf("Unable get PTP clock\n");
continue;
}
printf("Send PTP packet\n");
ret = ptp_clock_sendto(clockid, &addr, TX_TYPES, &tx_time);
if (ret < 0) {
printf("Unable send PTP packet\n");
}
}
/* 关闭时钟设备和socket */
ptp_clock_close(clockid);
close(sockfd);
return 0;
}
原创文章,作者:小蓝,如若转载,请注明出处:https://www.506064.com/n/283578.html
微信扫一扫
支付宝扫一扫