windows10搭建NTP服务器过程及验证测试

本文详细描述了如何在Windows11系统上配置NTP服务以进行时间同步,并提供了使用C语言编写的NTP客户端程序示例,用于验证与SNTP服务器的通信,以及跨平台编译步骤。
摘要由CSDN通过智能技术生成

记录工作实践:IEC61850协议通信过程中,需要通过SNTP协议进行对时功能,为验证此功能所以在windows11平台上面搭建NTP服务器,在开发板上面运行对时程序从而实现对时功能。

windows11搭建SNTP服务步骤:经查询Windows系统本身是可以作NTP时间同步服务器的,无需安装其它软件,只需要修改一些配置。

1.修改注册表:使用win + R 组合键在运行窗口中输入regedit,打开注册表编辑器。

2.修改以下注册表内容:

计算机\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\TimeProviders\NtpServer,把Enabled设置为1

计算机\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\Config,并把AnnounceFlags的值设置为5(系统默认为a)

3.启动NTP服务:通过管理员身份运行CMD命令行,依次输入命令

输入net stop w32time  输出以下信息表示没有打开NTP服务

输入net start w32time 启动服务,下图表示启动成功

4.本地测试

在cmd窗口中输入w32tm /stripchart /computer:192.168.1.100 ,如果有回显则服务正常。

以上表示为NTP服务搭建成功。

NTP服务功能测试:测试程序如下

1.sntp.c

#include "sntp.h"
struct s_fixedpt {
    uint16_t    intpart;
    uint16_t    fracpart;
};

struct l_fixedpt {
    uint32_t    intpart;
    uint32_t    fracpart;
};


struct ntphdr {
#if __BYTE_ORDER == __BID_ENDIAN
    unsigned int    ntp_li : 2;
    unsigned int    ntp_vn : 3;
    unsigned int    ntp_mode : 3;
#endif
#if __BYTE_ORDER == __LITTLE_ENDIAN
    unsigned int    ntp_mode : 3;
    unsigned int    ntp_vn : 3;
    unsigned int    ntp_li : 2;
#endif
    uint8_t         ntp_stratum;
    uint8_t         ntp_poll;
    int8_t          ntp_precision;
    struct s_fixedpt    ntp_rtdelay;
    struct s_fixedpt    ntp_rtdispersion;
    uint32_t            ntp_refid;
    struct l_fixedpt    ntp_refts;
    struct l_fixedpt    ntp_orits;
    struct l_fixedpt    ntp_recvts;
    struct l_fixedpt    ntp_transts;
};


in_addr_t inet_host(const char* host)
{
    in_addr_t saddr;
    struct hostent* hostent;

    if ((saddr = inet_addr(host)) == INADDR_NONE)
    {
        if ((hostent = gethostbyname(host)) == NULL)
            return INADDR_NONE;

        memmove(&saddr, hostent->h_addr, hostent->h_length);
    }

    return saddr;
}


int get_ntp_packet(void* buf, size_t* size)
{
    struct ntphdr* ntp;
    struct timeval tv;


    if (!size || *size < NTP_HLEN)
        return -1;

    memset(buf, 0, *size);

    ntp = (struct ntphdr*)buf;
    ntp->ntp_li = NTP_LI;
    ntp->ntp_vn = NTP_VN;
    ntp->ntp_mode = NTP_MODE;
    ntp->ntp_stratum = NTP_STRATUM;
    ntp->ntp_poll = NTP_POLL;
    ntp->ntp_precision = NTP_PRECISION;

    gettimeofday(&tv, NULL);
    ntp->ntp_transts.intpart = htonl(tv.tv_sec + JAN_1970);
    ntp->ntp_transts.fracpart = htonl(USEC2FRAC(tv.tv_usec));

    *size = NTP_HLEN;

    return 0;
}


void print_ntp(struct ntphdr* ntp)
{
    time_t time;

    printf("LI:\t%d \n", ntp->ntp_li);
    printf("VN:\t%d \n", ntp->ntp_vn);
    printf("Mode:\t%d \n", ntp->ntp_mode);
    printf("Stratum:\t%d \n", ntp->ntp_stratum);
    printf("Poll:\t%d \n", ntp->ntp_poll);
    printf("precision:\t%d \n", ntp->ntp_precision);

    printf("Route delay:\t %lf \n",
        ntohs(ntp->ntp_rtdelay.intpart) + NTP_REVE_FRAC16(ntohs(ntp->ntp_rtdelay.fracpart)));
    printf("Route Dispersion:\t%lf \n",
        ntohs(ntp->ntp_rtdispersion.intpart) + NTP_REVE_FRAC16(ntohs(ntp->ntp_rtdispersion.fracpart)));
    printf("Referencd ID:\t %d \n", ntohl(ntp->ntp_refid));


    time = ntohl(ntp->ntp_refts.intpart) - JAN_1970;
    printf("Reference:\t%d %ld %s \n",
        ntohl(ntp->ntp_refts.intpart) - JAN_1970,
        FRAC2USEC(ntohl(ntp->ntp_refts.fracpart)),
        ctime(&time));

    time = ntohl(ntp->ntp_orits.intpart) - JAN_1970;
    printf("Originate:\t%d %d frac=%ld (%s) \n",
        ntohl(ntp->ntp_orits.intpart) - JAN_1970,
        FRAC2USEC(ntohl(ntp->ntp_orits.fracpart)),
        ntohl(ntp->ntp_orits.fracpart),
        ctime(&time));

    time = ntohl(ntp->ntp_recvts.intpart) - JAN_1970;
    printf("Receive:\t%d %d (%s) \n",
        ntohl(ntp->ntp_recvts.intpart) - JAN_1970,
        FRAC2USEC(ntohl(ntp->ntp_recvts.fracpart)),
        ctime(&time));

    time = ntohl(ntp->ntp_transts.intpart) - JAN_1970;
    printf("Transmit:\t%d %d (%s) \n",
        ntohl(ntp->ntp_transts.intpart) - JAN_1970,
        FRAC2USEC(ntohl(ntp->ntp_transts.fracpart)),
        ctime(&time));
}


double get_rrt(const struct ntphdr* ntp, const struct timeval* recvtv)
{
    double t1, t2, t3, t4;

    t1 = NTP_LFIXED2DOUBLE(&ntp->ntp_orits);
    t2 = NTP_LFIXED2DOUBLE(&ntp->ntp_recvts);
    t3 = NTP_LFIXED2DOUBLE(&ntp->ntp_transts);
    t4 = recvtv->tv_sec + recvtv->tv_usec / 1000000.0;

    return (t4 - t1) - (t3 - t2);
}


double get_offset(const struct ntphdr* ntp, const struct timeval* recvtv)
{
    double t1, t2, t3, t4;

    t1 = NTP_LFIXED2DOUBLE(&ntp->ntp_orits);
    t2 = NTP_LFIXED2DOUBLE(&ntp->ntp_recvts);
    t3 = NTP_LFIXED2DOUBLE(&ntp->ntp_transts);
    t4 = recvtv->tv_sec + recvtv->tv_usec / 1000000.0;

    return ((t2 - t1) + (t3 - t4)) / 2;
}


void usage(void)
{
    fprintf(stderr,
        "Usage : ntpclient"
        " destination"
        "\n"
    );
}


int main()
{
    char buf[BUFSIZE];
    size_t nbytes;
    int sockfd, maxfd1;
    struct sockaddr_in servaddr;
    fd_set readfds;
    struct timeval timeout, recvtv, tv;
    double offset;

    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(NTP_PORT);
    servaddr.sin_addr.s_addr = inet_host(NTP_SERVER);

    if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
    {
        perror("socket error");
        exit(-1);
    }

    if (connect(sockfd, (struct sockaddr*)&servaddr, sizeof(struct sockaddr)) != 0)
    {
        perror("connect error");
        exit(-1);
    }

    nbytes = BUFSIZE;
    if (get_ntp_packet(buf, &nbytes) != 0)
    {
        fprintf(stderr, "construct ntp request error \n");
        exit(-1);
    }
    send(sockfd, buf, nbytes, 0);


    FD_ZERO(&readfds);
    FD_SET(sockfd, &readfds);
    maxfd1 = sockfd + 1;

    timeout.tv_sec = TIMEOUT;
    timeout.tv_usec = 0;

    if (select(maxfd1, &readfds, NULL, NULL, &timeout) > 0)
    {
        if (FD_ISSET(sockfd, &readfds))
        {
            if ((nbytes = recv(sockfd, buf, BUFSIZE, 0)) < 0)
            {
                perror("recv error");
                exit(-1);
            }
            //计算客户端时间与服务器端时间偏移量
            gettimeofday(&recvtv, NULL);
            offset = get_offset((struct ntphdr*)buf, &recvtv);
            //更新系统时间
            gettimeofday(&tv, NULL);
            tv.tv_sec += (int)offset;
            tv.tv_usec += offset - (int)offset;

            if (settimeofday(&tv, NULL) != 0)
            {
                perror("settimeofday error");
                exit(-1);
            }
            
            /*printf("time=%s\n", ctime((time_t*)&tv.tv_sec));
            char time_string[80];
            strftime(time_string, sizeof(time_string), "%Y-%m-%d %H:%M:%S", localtime(&tv.tv_sec));
            printf("date -s %s\n", time_string);*/
        }
    }

    close(sockfd);

    return 0;
}

sntp.h 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <errno.h>
#include <endian.h>

#define VERSION_3           3
#define VERSION_4           4
#define MODE_CLIENT         3
#define MODE_SERVER         4
#define NTP_LI              0
#define NTP_VN              VERSION_3   
#define NTP_MODE            MODE_CLIENT
#define NTP_STRATUM         0
#define NTP_POLL            4
#define NTP_PRECISION       -6
#define NTP_HLEN            48
#define NTP_PORT            123
#define NTP_SERVER          "192.168.1.100"
#define TIMEOUT             10
#define BUFSIZE             1500
#define JAN_1970            0x83aa7e80
#define NTP_CONV_FRAC32(x)  (uint64_t) ((x) * ((uint64_t)1<<32))    
#define NTP_REVE_FRAC32(x)  ((double) ((double) (x) / ((uint64_t)1<<32)))   
#define NTP_CONV_FRAC16(x)  (uint32_t) ((x) * ((uint32_t)1<<16))    
#define NTP_REVE_FRAC16(x)  ((double)((double) (x) / ((uint32_t)1<<16)))    
#define USEC2FRAC(x)        ((uint32_t) NTP_CONV_FRAC32( (x) / 1000000.0 )) 
#define FRAC2USEC(x)        ((uint32_t) NTP_REVE_FRAC32( (x) * 1000000.0 )) 
#define NTP_LFIXED2DOUBLE(x)    ((double) ( ntohl(((struct l_fixedpt *) (x))->intpart) - JAN_1970 + FRAC2USEC(ntohl(((struct l_fixedpt *) (x))->fracpart)) / 1000000.0 ))   

2.通过交叉编译工具生成可执行程序。aarch64-linux-gnu-gcc ntp_time.c -o ntp -lpthread 交叉编译工具需与编译平台保持一致。

以下为输出结果。

在Windows 10上配置NTP服务器的方法如下: 1. 打开命令提示符,输入命令"w32tm /stripchart /computer:127.0.0.1",如果有时间回显,说明配置成功了。这样就在Windows 10上配置了NTP时间同步服务器。\[1\] 2. 打开“设置”菜单,点击“时间和语言”,然后点击“日期和时间”选项。 3. 在日期和时间设置页面,将“与Internet时间服务器同步”的复选框选中。 4. 在服务器框内填入可用的NTP服务器地址,然后点击“立即更新”按钮,即可完成与网络内的NTP服务器进行时间同步。点击“确定”即完成NTP客户端的配置。\[2\] 需要注意的是,Windows 10默认与NTP服务器对时间同步的间隔为24小时。如果需要调整对时间同步的间隔,可以通过以下步骤进行配置: 1. 在开始菜单中搜索并打开“注册表编辑器”(regedit)。 2. 在注册表编辑器中,依次展开"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\TimeProviders\NtpClient"。 3. 在右侧找到“SpecialPollInterval”,双击打开。 4. 在“基数”处选择十进制,在“数值”处填入需要的对时间同步的间隔,单位为秒。完成后点击“确定”即完成配置。\[3\] 这样,你就成功配置了Windows 10上的NTP服务器。 #### 引用[.reference_title] - *1* *2* *3* [WINDOWS 10如何配置NTP服务(Server&Client)](https://blog.csdn.net/hulangbotufei/article/details/125253825)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值