一、什麼是網路時間協議
網路時間協議(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/zh-tw/n/283578.html
微信掃一掃
支付寶掃一掃