NTP(Network Time Protocol 网络时间协议)

作用

        大数据产生与处理系统是各种计算设备集群的,计算设备将统一、同步的标准时间用于记录各种事件发生时序,如 E-MAIL 信息、文件创建和访问时间、数据库处理时间等。大数据系统内不同计算设备之间控制、计算、处理、应用等数据或操作都具有时序性,若计算机时间不同步,这些应用或操作或将无法正常进行。大数据系统是对时间敏感的计算处理系统,时间同步是大数据能够得到正确处理的基础保障,是大数据得以发挥作用的技术支撑。大数据时代,整个处理计算系统内的大数据通信都是通过网络进行。时间同步也是如此,利用大数据的互联网络传送标准时间信息,实现大数据系统内时间同步。网络时间同步协议(NTP)是时间同步的技术基础。
        NTP 是用来获取网络时间,它是一个 UDP 服务器,你给它发送一个正确格式的数据,他就会回复你
        在 CentOS8.0 中默认不再支持 ntp 软件包,时间同步将由 chrony 来实现。chrony 是一种相对于 ntp 更好的时间同步程序。
        全球一共有很多 NTP 服务器,例如我们去网上搜索 NTP 服务器就会看到:
NTP(Network Time Protocol 网络时间协议)_第1张图片
NTP 服务器一般使用的端口号为 123
NTP 的协议格式:
NTP packet = NTP header(16 字节) + 4 个时间戳(每个 8 字节) = 48 字节
其中 NTP header 的顺序格式:
LI | VN |Mode | Stratum | Poll | Precision |Root Delay |Root Dispersion |Reference Identifier
Li - LeapYearIndicator : 2bit
VN - VersionNumber : 3bit
Mode : 3 bit
Stratum : 8bit
Poll - PollInterval : 8 bit
Percision : 8bit
Root delay : 32bit
Root Dispersion : 32bit
Reference Identifier : 32bit
主要字段的解释如下:
LI(Leap Indicator):长度为 2 比特,值为“11”时表示告警状态,时钟未被同步。为其他值时 NTP 本身不做处理。
VN(Version Number):长度为 3 比特,表示 NTP 的版本号,目前的最新版本为 3。
Mode:长度为 3 比特,表示 NTP 的工作模式。不同的值所表示的含义分别是:0 未定义、1 表示主动对等体模式、2 表示被动对等体模式、3 表示客户模式、4 表示服务器模式、5 表示广播模 式或组播模式、6 表示此报文为 NTP 控制报文、7 预留给内部使用。
Stratum:系统时钟的层数,取值范围为 1~16,它定义了时钟的准确度。层数为 1 的时钟准确度最高,准确度从 1 到 16 依次递减,层数为 16 的时钟处于未同步状态,不能作为参考时钟。
Poll:轮询时间,即两个连续 NTP 报文之间的时间间隔。
Precision:系统时钟的精度。
Root Delay:本地到主参考时钟源的往返时间。
Root Dispersion:系统时钟相对于主参考时钟的最大误差。
Reference Identifier:参考时钟源的标识。
Reference Timestamp:系统时钟最后一次被设定或更新的时间。
Originate Timestamp:NTP 请求报文离开发送端时发送端的本地时间。
Receive Timestamp:NTP 请求报文到达接收端时接收端的本地时间。
Transmit Timestamp:应答报文离开应答者时应答者的本地时间。
Authenticator:验证信息。
四个时间戳(TimeStamps) : 共 32 字节
Reference Timestamp : 64bit 提出时间
Originate Timestamp : 64bit 客户端发送请求的时间
Receive Timestamp : 64bit 服务器接收请求的时间
Transmit Timestamp : 64bit 服务器答复时间
知道上面格式我们就可以通过 UDP 发送协议报文给 NTP 服务器获取时间信息

实例程序

#include
#include  /* See NOTES */
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

//秒---》时间字符串
//ctime 1970 1 1 到现在的秒数
//网络时间 1900 1 1 

#define NTP_SEC 2208988800ull // 1900~1970 年时间差

int main(int argc,char *argv[])
{
    //创建一个套接字
    int sock = socket(AF_INET, SOCK_DGRAM, 0);
    if(sock == -1)
    {
        perror("socket error");
        return -1;
    }

    //2.初始化一个目的地的 IPV4 结构体,你的服务器的地址
    // prot:123 阿里云 NTP 服务器:182.92.12.11
    struct sockaddr_in sAddr;
    memset(&sAddr,0,sizeof(sAddr));//内存设置
    sAddr.sin_family = AF_INET; //指定协议族 AF_INET
    sAddr.sin_port = htons(atoi(argv[1])); //端口号
    //sAddr.sin_addr; //ip 地址
    //inet_aton(argv[2],&(sAddr.sin_addr));
    sAddr.sin_addr.s_addr = inet_addr(argv[2]);

    unsigned char buf[48] = {0};
    buf[0] = 0x1b;
    //发送消息
    int res = sendto(sock,buf, 48, 0,(struct sockaddr*)&sAddr,sizeof(sAddr));
    struct sockaddr_in sa;
    socklen_t addrlen = sizeof(sa);
    res = recvfrom(sock,buf,48,0,(struct sockaddr *)&sa,&addrlen);
    if(res >0)
    {
        printf("res = %d\n",res);
        printf("server IP:%s
        prot:%d\n",inet_ntoa(sa.sin_addr),ntohs(sa.sin_port));
        //printf("recv message:%s\n",buf1);
        unsigned int rec_sec = *(int *)(buf+40);//网络字节序
        rec_sec = ntohl(rec_sec);
        time_t cur_sec = rec_sec-NTP_SEC;//1970 到现在
        printf("%s\n",ctime(&cur_sec));
    }
    close(sock);
    return 0;
}

你可能感兴趣的:(LINUX网络编程分享,网络)