VxWorks中如何实现时间同步

作者:佚名 上传时间:2023-05-19 运行软件:Wind River 软件版本:VxWorks 7.0 版权申诉

在嵌入式领域,时间同步是非常重要的一项功能。本示例展示了如何在VxWorks系统下使用NTP协议实现时间同步。使用NTP协议可以从网络时间服务器上获取时间信息进行同步。

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>

#define NTP_PORT                     123
#define NTP_MAX_LI_VN_MODE           0x1C
#define NTP_MAX_STRATUM              15
#define NTP_MAX_POLL                 10
#define NTP_MIN_PRECISION            -20
#define NTP_MAX_PRECISION            20
#define NTP_MAX_DELAY                0.1
#define NTP_BIND_TIMEOUT_SEC         3
#define NTP_MANAGE_INTERVAL_SEC      5
#define NTP_TIME_EPOCH_OFFSET        2208988800ull

static void ntpManageTask(int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7, int arg8, int arg9, int arg10);
static BOOL ntpBind(int *pSockFd);
static BOOL ntpGetServerAddr(int sockFd, struct sockaddr_in *pServerAddr, char *pServerName);
static BOOL ntpBuildQuery(char *pQuery, int queryLen);
static BOOL ntpParseReply(char *pReply, int replyLen, struct timespec *pTimeStamp);
static BOOL ntpUpdateLocalTime(struct timespec *pTimeStamp);

//启动时间同步管理任务
void ntpStartSync(void)
{
    taskSpawn("tNtpSync", NTP_TASK_PRIORITY, NTP_TASK_OPTIONS,
              NTP_TASK_STACK_SIZE, (FUNCPTR)ntpManageTask,
              0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
}

//时间同步管理任务
static void ntpManageTask(int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7, int arg8, int arg9, int arg10)
{
    struct timespec ts;
    int sockFd;
    struct sockaddr_in serverAddr;
    char serverName[NTP_SERVER_NAME_LEN];

    memset(&ts, 0, sizeof(ts));

    //创建NTP套接字并绑定
    if (FALSE == ntpBind(&sockFd)) {
        goto TASK_EXIT;
    }

    //设置服务器名称
    strncpy(serverName, NTP_SERVER_DEFAULT, sizeof(serverName));

    while (1) {
        //获取服务器地址
        if (FALSE == ntpGetServerAddr(sockFd, &serverAddr, serverName)) {
            goto TASK_EXIT;
        }

        //构建NTP报文查询服务器时间
        if (FALSE == ntpBuildQuery(NTP_QUERY_DEFAULT, sizeof(NTP_QUERY_DEFAULT))) {
            goto TASK_EXIT;
        }

        //发送查询报文并解析响应报文
        if (FALSE == ntpParseReply(NTP_REPLY_DEFAULT, sizeof(NTP_REPLY_DEFAULT), &ts)) {
            goto TASK_EXIT;
        }

        //更新本地时间
        if (FALSE == ntpUpdateLocalTime(&ts)) {
            goto TASK_EXIT;
        }

        //更新下一次同步的服务器名称
        strncpy(serverName, NTP_SERVER_DEFAULT, sizeof(serverName));

        //等待下一次同步时间
        taskDelay(NTP_MANAGE_INTERVAL_SEC * sysClkRateGet());
    }

TASK_EXIT:
    printf("NTP manage task exit.\n");

    if (sockFd >= 0) {
        close(sockFd);
    }
}

//绑定NTP套接字
static BOOL ntpBind(int *pSockFd)
{
    struct sockaddr_in sockAddr;
    struct timeval timeVal;
    fd_set fdSet;
    int sockFd = -1;
    int ret = -1;

    //创建NTP套接字
    sockFd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (sockFd < 0) {
        printf("create NTP socket fail, errno=%d.\n", errno);
        return FALSE;
    }

    timeVal.tv_sec = NTP_BIND_TIMEOUT_SEC;
    timeVal.tv_usec = 0;

    FD_ZERO(&fdSet);
    FD_SET(sockFd, &fdSet);

    //设置套接字绑定超时时间
    setsockopt(sockFd, SOL_SOCKET, SO_RCVTIMEO, &timeVal, sizeof(timeVal));

    memset(&sockAddr, 0, sizeof(sockAddr));
    sockAddr.sin_family = AF_INET;
    sockAddr.sin_addr.s_addr = htonl(INADDR_ANY);
    sockAddr.sin_port = htons(NTP_PORT);

    //绑定NTP套接字
    ret = bind(sockFd, (struct sockaddr *)&sockAddr, sizeof(sockAddr));
    if (ret < 0) {
        printf("bind NTP socket fail, errno=%d.\n", errno);
        close(sockFd);
        return FALSE;
    }

    *pSockFd = sockFd;

    return TRUE;
}

//获取服务器地址
static BOOL ntpGetServerAddr(int sockFd, struct sockaddr_in *pServerAddr, char *pServerName)
{
    struct hostent *pHostEnt;
    BOOL isNumeric;
    in_addr_t serverAddr;
    int ret;

    //判断服务器名称为IP地址的情况
    isNumeric = inet_pton(AF_INET, pServerName, &serverAddr);
    if (isNumeric) {
        pServerAddr->sin_addr.s_addr = serverAddr;
    } else {
        //查询DNS服务器获取IP地址
        pHostEnt = gethostbyname(pServerName);
        if (NULL == pHostEnt) {
            printf("get NTP server address fail, errno=%d.\n", errno);
            return FALSE;
        }

        memcpy(&pServerAddr->sin_addr, pHostEnt->h_addr_list[0], pHostEnt->h_length);
    }

    //设置服务器套接字地址族和端口号
    pServerAddr->sin_family = AF_INET;
    pServerAddr->sin_port = htons(NTP_PORT);

    return TRUE;
}

//构建NTP报文查询服务器时间
static BOOL ntpBuildQuery(char *pQuery, int queryLen)
{
    uint8_t *pPacket = (uint8_t *)pQuery;
    struct timespec ts;
    time_t secs;
    uint32_t frac;
    int ret;

    //校验报文长度
    if (queryLen != NTP_QUERY_LEN) {
        printf("invalid query length.\n");
        return FALSE;
    }

    //构建64位的NTP时间戳
    clock_gettime(CLOCK_REALTIME, &ts);
    secs = ts.tv_sec + NTP_TIME_EPOCH_OFFSET;
    frac = (uint64_t)ts.tv_nsec * ((uint32_t)1 << 32) / 1000000000;

    //填充NTP报文头部
    pPacket[0] = NTP_MAX_LI_VN_MODE;
    pPacket[1] = NTP_MAX_STRATUM;
    pPacket[2] = NTP_MAX_POLL;
    pPacket[3] = NTP_MIN_PRECISION;
    memcpy(pPacket + 4, &precision, sizeof(precision));
    memcpy(pPacket + 8, &delay, sizeof(delay));
    memcpy(pPacket + 12, &pcs, sizeof(pcs));
    memcpy(pPacket + 16, &ocs, sizeof(ocs));

    ret = htonl((uint32_t)secs);
    memcpy(pPacket + 40, &ret, sizeof(ret));

    ret = htonl((uint32_t)frac);
    memcpy(pPacket + 44, &ret, sizeof(ret));

    return TRUE;
}

//解析NTP响应报文
static BOOL ntpParseReply(char *pReply, int replyLen, struct timespec *pTimeStamp)
{
    struct timespec ts;
    uint8_t *pPacket = (uint8_t *)pReply;
    uint32_t secPart;
    uint32_t fracPart;
    int ret;

    //校验报文长度
    if (replyLen != NTP_REPLY_LEN) {
        printf("invalid reply length.\n");
        return FALSE;
    }

    //解析服务器返回的NTP时间戳
    memcpy(&secPart, pPacket + 40, sizeof(secPart));
    memcpy(&fracPart, pPacket + 44, sizeof(fracPart));

    ts.tv_sec = ntohl(secPart) - NTP_TIME_EPOCH_OFFSET;
    ts.tv_nsec = ((uint64_t)ntohl(fracPart) * 1000000000) >> 32;

    *pTimeStamp = ts;

    return TRUE;
}

//更新本地时间
static BOOL ntpUpdateLocalTime(struct timespec *pTimeStamp)
{
    struct timespec ts;
    int ret;

    clock_gettime(CLOCK_REALTIME, &ts);
    ts.tv_sec = pTimeStamp->tv_sec;
    ts.tv_nsec = pTimeStamp->tv_nsec;

    //设置系统时间
    ret = clock_settime(CLOCK_REALTIME, &ts);
    if (ret < 0) {
        printf("set system time fail, errno=%d.\n", errno);
        return FALSE;
    }

    return TRUE;
}

免责申明:文章和图片全部来源于公开网络,如有侵权,请通知删除 server@dude6.com

用户评论
相关推荐
VxWorks如何实现系统时间同步
VxWorks是一个实时操作系统,为了保证系统的正确运行,需要对系统时间进行同步。本示例代码将介绍如何在VxWorks中使用SNTP协议实现系统时间同步。#include <sntpcLib.
VxWorks 6.9
Wind River Systems
2023-04-01 07:20
VxWorks如何实现时间同步
在嵌入式领域,时间同步是非常重要的一项功能。本示例展示了如何在VxWorks系统下使用NTP协议实现时间同步。使用NTP协议可以从网络时间服务器上获取时间信息进行同步。#include <sy
VxWorks 7.0
Wind River
2023-05-19 08:51
如何使用ntp时间同步服务实现网络时间同步
网络时间同步对于计算机系统的稳定性和准确性至关重要,而ntp时间同步服务是实现网络时间同步的关键。本文将介绍ntp时间同步服务的原理和使用方法,帮助读者理解和运用这一功能。首先,我们将详细解释ntp时
txt
2.02KB
2023-10-04 16:51
VxWorks实现时间同步的方法
本示例代码实现了VxWorks系统中实现与NTP服务器的时间同步的方法,通过设置VxWorks系统中的时间服务参数,将与NTP服务器进行时间校准同步,确保VxWorks系统中的时钟与NTP服务器时间同
VxWorks 6.9
Wind River Systems
2023-05-22 20:16
VxWorks如何实现线程同步
本示例展示了使用VxWorks中的信号量实现线程同步的方法,通过对信号量的P和V操作,实现线程的阻塞和唤醒。#include "vxWorks.h"#include "
VxWorks 6.9
Wind River Systems
2023-05-23 08:30
Vxworks设定时间
VxWorks的系统时间设定。从BIOS中取得时间,并设定系统的时间为该标准时间。
C
0B
2020-05-24 19:30
VxWorks如何实现多线程同步
在VxWorks中,多线程同步是一项非常重要的任务。为了确保多个线程之间的互斥和同步,VxWorks提供了多种同步机制。本文将介绍VxWorks中如何实现多线程同步,包括示例代码、代码释义和总结。示
VxWorks 7
C
2023-04-05 16:25
VxWorks实现时间同步的解决方案
这是一种VxWorks操作系统下实现时间同步的解决方案,可以通过将系统时间同步到NTP服务器来保证系统的时间准确性。实现方式为通过SNTP协议从NTP服务器获取时间并同步到本地系统。#include
VxWorks 6.x
Wind River Systems
2023-03-18 13:38
如何实现C#歌词同步显示
在C#编程中,如何通过加载相应的文件或在数据库中保存相应信息实现歌曲和歌词同名,并在label控件中实现同步显示。同时,为了确保同步,需在歌词中加入时间标记。详细步骤如下:1.加载歌曲及相应的歌词文件
TXT
0B
2018-12-07 06:41
同步系统时间功能实现
通过获取NTP服务器的时间,设置Android系统时间;里面用到系统权限,所以需要系统签名key。
RAR
0B
2019-04-13 21:38