LINUX获取NTP时间

最近在学习Linux的网络编程,做了个获取NTP时间的小实例可做参考

1.NTP协议格式

2.需要构造NTP协议包发送给服务器,需要包括一些必要的字段

3.源代码如下:

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

//可用的NTP地址:202.112.31.197(time.edu.cn)还有很多可用的

#define gap_1900_1970 0x83aa7e80 
//NTP时间从1970开始 比我们计算机常用的UTC早 秒数更多

#define USEC_TO_UINT32(x) ((uint32_t)(((uint64_t)(x)<<32)/1000000))
//将微妙整数转化为小数秒

#define UINT32_TO_USEC(x) ((uint32_t)(((double)ntohl(x)/((uint64_t)1<<32))*1000000)) 
//将网络字节序转化为主机字节序 小数秒转化为微秒整数

typedef struct _uint64_time
{
    uint32_t int_part;
    uint32_t float_part;
} uint64_time;

typedef struct _NTP_time
{
    unsigned char leap_ver_mode;
    unsigned char stratum;
    char poll;
    char precision;
    int32_t root_delay;
    int32_t root_dispersion;
    int32_t reference_identifine;
    uint64_time reference_time;
    uint64_time original_time;
    uint64_time receive_time;
    uint64_time transmit_time;
} NTP_time, *NTP_time_Ptr;

void get_NTP(NTP_time *ntp_time);
void print_NTP(NTP_time* ntp_time);

int main(int argc,char *argv[])
{
    NTP_time ntp_time;
    int socket_fd,sendtypes,recvtypes,pton_temp = 0,select_temp;
    struct sockaddr_in server_addr;
    unsigned char recvbuf[48] = {0x00};
    
    if(argc!=2)
    {
        printf("main parameters is wrong! please use 2!\n");
        exit(EXIT_FAILURE);
    }
    
    get_NTP(&ntp_time);
    
    socket_fd = socket(AF_INET,SOCK_DGRAM,0);
    if(socket_fd == -1) 
    {
        perror("Socket failed");  
        exit(EXIT_FAILURE);
    }
    
    memset(&server_addr,0x00,sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(123);
    pton_temp = inet_pton(AF_INET,argv[1],&server_addr.sin_addr);
    if(pton_temp!=1)
    {
        perror("Pton failed");
        exit(EXIT_FAILURE);
    }
    
    sendtypes = sendto(socket_fd,&ntp_time,sizeof(NTP_time),0,(struct sockaddr *)&server_addr,sizeof(server_addr));
    if(sendtypes == -1) 
    {
        perror("Sendto failed");
        close(socket_fd);
        exit(EXIT_FAILURE);
    }
    
    fd_set read_fds;
    struct timeval timeout;
    timeout.tv_sec = 1;
    timeout.tv_usec = 0;//设置超时时间1s
    FD_ZERO(&read_fds);
    FD_SET(socket_fd, &read_fds);
    
    select_temp = select(socket_fd + 1, &read_fds, NULL, NULL, &timeout);
    if(select_temp > 0)
    {
        recvtypes = recvfrom(socket_fd,recvbuf,sizeof(recvbuf),0,NULL,NULL);
        if(recvtypes == -1) 
        {
            perror("Recvfrom failed");
            close(socket_fd);
            exit(EXIT_FAILURE);
        }
        NTP_time_Ptr ntp_time_ptr = (NTP_time_Ptr)(recvbuf);
        (void)print_NTP(ntp_time_ptr);
    }
    else
    {
        perror("select:no data!");
        close(socket_fd);
        exit(EXIT_FAILURE);
    }
    
    close(socket_fd);
    return 0;
}

void get_NTP(NTP_time *ntp_time)
{
    struct timeval tv;
    memset(ntp_time,0x00,sizeof(NTP_time));
    ntp_time->leap_ver_mode = 0x1b;
    ntp_time->stratum = 0;
    ntp_time->poll = 4;
    ntp_time->precision = -6;
    gettimeofday(&tv, NULL);
    ntp_time->transmit_time.int_part = htonl(tv.tv_sec + gap_1900_1970);
    ntp_time->transmit_time.float_part = htonl(USEC_TO_UINT32(tv.tv_usec));
}

void print_NTP(NTP_time* ntp_time)
{
    printf("leap_ver_mode: %d\n",ntp_time->leap_ver_mode);
    printf("stratum: %d\n",ntp_time->stratum);
    printf("poll: %d\n",ntp_time->poll);
    printf("precision: %d\n",ntp_time->precision);
    printf("reference time: %us %dms\n",ntohl(ntp_time->reference_time.int_part)-gap_1900_1970,UINT32_TO_USEC(ntp_time->reference_time.float_part)/1000);
    printf("original time:  %us %dms\n",ntohl(ntp_time->original_time.int_part)-gap_1900_1970,UINT32_TO_USEC(ntp_time->original_time.float_part)/1000);    
    printf("receive time:   %us %dms\n",ntohl(ntp_time->receive_time.int_part)-gap_1900_1970,UINT32_TO_USEC(ntp_time->receive_time.float_part)/1000);
    printf("transmit time:  %us %dms\n",ntohl(ntp_time->transmit_time.int_part)-gap_1900_1970,UINT32_TO_USEC(ntp_time->transmit_time.float_part)/1000);
}
在Ubuntu下编译即可运行,第二个参数需要指定NTP服务器的ipv4地址

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值