NTP协议详解_ntp是安全协议吗

NTP协议详解_ntp是安全协议吗前言NTP(NetworkTimeProtocol)网络时间协议基于UDP,用于网络时间同步的协议,使网络中的计算机时钟同步到UTC,再配合各个时区的偏移调整就能实现精准同步对时功能。提供NTP对时的服务器有很多,比如微软的NTP对时服务器,利用NTP服务器提供的对时功能,可以使我们的设备时钟系统能够正确运行。NTP报文格式NTP报文格式如上图所示,它的字段含义参考如下:L…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE稳定放心使用

前言

NTP(Network Time Protocol)网络时间协议基于UDP,用于网络时间同步的协议,使网络中的计算机时钟同步到UTC,再配合各个时区的偏移调整就能实现精准同步对时功能。提供NTP对时的服务器有很多,比如微软的NTP对时服务器,利用NTP服务器提供的对时功能,可以使我们的设备时钟系统能够正确运行。

NTP报文格式

NTP协议详解_ntp是安全协议吗

NTP报文格式如上图所示,它的字段含义参考如下:

  1. LI 闰秒标识器,占用2个bit
  2. VN 版本号,占用3个bits,表示NTP的版本号,现在为3
  3. Mode 模式,占用3个bits,表示模式
  4. stratum(层),占用8个bits
  5. Poll 测试间隔,占用8个bits,表示连续信息之间的最大间隔
  6. Precision 精度,占用8个bits,,表示本地时钟精度
  7. Root Delay根时延,占用8个bits,表示在主参考源之间往返的总共时延
  8. Root Dispersion根离散,占用8个bits,表示在主参考源有关的名义错误
  9. Reference Identifier参考时钟标识符,占用8个bits,用来标识特殊的参考源    
  10. 参考时间戳,64bits时间戳,本地时钟被修改的最新时间。
  11. 原始时间戳,客户端发送的时间,64bits。
  12. 接受时间戳,服务端接受到的时间,64bits。
  13. 传送时间戳,服务端送出应答的时间,64bits。
  14. 认证符(可选项)

NTP协议详解_ntp是安全协议吗

抛开复杂的协议报文,我们来理解一下NTP客户端与服务器的交互过程,进而理解参考时间戳、原始时间戳、接受时间戳、传送时间戳的关系。如图,客户端和服务端都有一个时间轴,分别代表着各自系统的时间,当客户端想要同步服务端的时间时,客户端会构造一个NTP协议包发送到NTP服务端,客户端会记下此时发送的时间t0,经过一段网络延时传输后,服务器在t1时刻收到数据包,经过一段时间处理后在t2时刻向客户端返回数据包,再经过一段网络延时传输后客户端在t3时刻收到NTP服务器数据包。特别声明,t0和t3是客户端时间系统的时间、t1和t2是NTP服务端时间系统的时间,它们是有区别的。对于时间要求不那么精准设备,直接使用NTP服务器返回t2时间也没有太大影响。但是作为一个标准的通信协议,它是精益求精且容不得过多误差的,于是必须计算上网络的传输延时。客户端与服务端的时间系统的偏移定义为θ、网络的往返延迟定义为δ,基于此,可以对t2进行精确的修正,已达到相关精度要求,它们的计算公式如下:

NTP协议详解_ntp是安全协议吗

式中:

t0是请求数据包传输的客户端时间戳

t1是请求数据包回复的服务器时间戳

t2是响应数据包传输的服务器时间戳

t3是响应数据包回复的客户端时间戳

对此,我们只需将NTP服务端返回的时间t2加上网络延时δ的一半就可以了(t2+δ/2)。

NTP请求样例

#include <sys/types.h>  
#include <sys/stat.h> 
#include <sys/ioctl.h> 
#include <sys/socket.h>
#include <sys/wait.h> 
#include <sys/time.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h> 
#include <stdio.h>  
#include <stdlib.h>
#include <string.h>  
#include <pthread.h>   
#include <dirent.h> 
#include <time.h>
#include <fcntl.h> 
#include <errno.h>

#define debugprintf 1
#ifdef debugprintf
	#define debugpri(mesg, args...) fprintf(stderr, "[NetRate print:%s:%d:] " mesg "\n", __FILE__, __LINE__, ##args) 
#else
	#define debugpri(mesg, args...)
#endif

#define JAN_1970     		0x83aa7e80
#define NTPFRAC(x) (4294 * (x) + ((1981 * (x))>>11))
#define USEC(x) (((x) >> 12) - 759 * ((((x) >> 10) + 32768) >> 16))
#define Data(i) ntohl(((unsigned int *)data)[i])
#define LI 0
#define VN 3
#define MODE 3
#define STRATUM 0
#define POLL 4 
#define PREC -6
struct NtpTime 
{
	unsigned int coarse;
	unsigned int fine;
};

void sendPacket(int fd)
{
	unsigned int data[12];
	struct timeval now;

	if (sizeof(data) != 48) 
	{
    	fprintf(stderr,"size error\n");
    	return;
	}

	memset((char*)data, 0, sizeof(data));
	data[0] = htonl((LI << 30) | (VN << 27) | (MODE << 24) | (STRATUM << 16) | (POLL << 8) | (PREC & 0xff));//构造协议头部信息
	data[1] = htonl(1<<16);
	data[2] = htonl(1<<16);
	gettimeofday(&now, NULL);
	data[10] = htonl(now.tv_sec + JAN_1970);//构造传输时间戳
	data[11] = htonl(NTPFRAC(now.tv_usec));
	send(fd, data, 48, 0);
}
//获取NTP服务器返回的时间
void getNewTime(unsigned int *data,struct timeval *ptimeval)
{
	struct NtpTime trantime;
	trantime.coarse = Data(10);
	trantime.fine   = Data(11);
	
	ptimeval->tv_sec 	= trantime.coarse - JAN_1970;
	ptimeval->tv_usec 	= USEC(trantime.fine);
}

int getNtpTime(struct hostent* phost,struct timeval *ptimeval)
{
	if(phost == NULL)
	{
		debugpri("err:host is null!\n");
		return -1;
	}
	int sockfd;
	struct sockaddr_in addr_src,addr_dst;
	fd_set fds;
	int ret;
	int recv_len;
	unsigned int buf[12];
	memset(buf,0,sizeof(buf));
	int addr_len;
	int count = 0;
	
	struct timeval timeout;

	addr_len = sizeof(struct sockaddr_in);

	memset(&addr_src, 0, addr_len);
	addr_src.sin_family = AF_INET;
	addr_src.sin_addr.s_addr = htonl(INADDR_ANY);
	addr_src.sin_port = htons(0);

	memset(&addr_dst, 0, addr_len);
	addr_dst.sin_family = AF_INET;
	memcpy(&(addr_dst.sin_addr.s_addr), phost->h_addr_list[0], 4);
	addr_dst.sin_port = htons(123);//ntp默认端口123

	if(-1==(sockfd = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP)))//创建UDP socket
	{		
		debugpri("create socket error!\n");
		return -1;
	}

	ret = bind(sockfd, (struct sockaddr*)&addr_src, addr_len);//bind
	if(-1==ret)	
	{		
		debugpri("bind error!\n");		
		close(sockfd);		
		return -1;
	}
	
	ret = connect(sockfd, (struct sockaddr*)&addr_dst, addr_len);//连接NTP服务器
	if(-1==ret)	
	{		
		debugpri("connect error!\n");		
		close(sockfd);		
		return -1;
	}
	sendPacket(sockfd);	//发送请求包
	while (count < 50)//轮询请求
	{
		FD_ZERO(&fds);
		FD_SET(sockfd, &fds);

		timeout.tv_sec = 0;
		timeout.tv_usec = 100000;
		ret = select(sockfd + 1, &fds, NULL, NULL, &timeout);
		if (0 == ret)
		{
			count++;
			debugpri("ret == 0\n");
			sendPacket(sockfd);
			usleep(100*1000);
			continue;
		}
		if(FD_ISSET(sockfd, &fds))
		{
			recv_len = recvfrom(sockfd, buf, sizeof(buf), 0, (struct sockaddr *)&addr_dst, (socklen_t*)&addr_len);
			if(-1==recv_len)		
			{			
				debugpri("recvfrom error\n");			
				close(sockfd);			
				return -1;
			}
			else if(recv_len > 0)
			{
				debugpri("receiv data\n");
				getNewTime(buf,ptimeval);
				debugpri("sec = %d usec = %d",ptimeval->tv_sec ,ptimeval->tv_usec);//打印输出NTP服务器返回的时间
				break;
			}
		}
		else
		{
			debugpri("count %d \n",count);
			usleep(50*1000);
			count ++;
		}
	}
	if(count >=50)
	{
		debugpri("getNewTime   timeout fail \n");
		close(sockfd);
		return -1;
	}
	close(sockfd);
	return 0;
}

int main(int argc, char** argv)  
{
	struct timeval TimeSet;
	static struct hostent *host = NULL;
	
	host = gethostbyname(argv[1]);
	memset(&TimeSet ,0 ,sizeof(TimeSet));
	getNtpTime(host,&TimeSet);
	return 0;
	 
 }

常用的NTP服务端站点

time.windows.com

time.nist.gov

s1a.time.edu.cn

s1c.time.edu.cn

time-nw.nist.gov

time-a.nist.gov

time-b.nist.gov

s1b.time.edu.cn

nist1.aol-ca.truetime.com

总结:

NTP协议作为常用的通信协议,各种参考资料齐全,本文做一次梳理,以加深对NTP协议的理解。参考:

https://zh.m.wikipedia.org/wiki/%E7%B6%B2%E8%B7%AF%E6%99%82%E9%96%93%E5%8D%94%E5%AE%9A

https://wenku.baidu.com/view/4ab65c3ec850ad02de80418e.html

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/182662.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • JS 匿名函数——几种不同的调用方式[通俗易懂]

    JS 匿名函数——几种不同的调用方式[通俗易懂]匿名函数有两种用法: 1.赋值 vara=function(){}; 2.自我执行这里我总结了4种匿名函数调用方法: //1. functionshow(){ document.write(‘nihao’); } show(); //2. (function(){ document.write(‘wohao’); })();…

    2022年10月4日
    1
  • TEXT、TINYTEXT、MEDIUMTEXT、LONGTEXT选择 和 char varchar varchar2 的区别[通俗易懂]

    TEXT、TINYTEXT、MEDIUMTEXT、LONGTEXT选择 和 char varchar varchar2 的区别[通俗易懂]TEXT、TINYTEXT、MEDIUMTEXT、LONGTEXT选择:储存不区分大小写的字符数据TINYTEXT最大长度是255(2^8-1)个字符。TEXT最大长度是65535(2^16-1)个字符。MEDIUMTEXT最大长度是16777215(2^24-1)个字符。LONGTEXT最大长度是4294967295(2^32-1

    2022年8月13日
    5
  • 自建电驴服务器,电驴服务器怎么连接 eMule连接服务器教程

    自建电驴服务器,电驴服务器怎么连接 eMule连接服务器教程电驴(eMule)是一款非常实用的资源下载工具。但有时候用户会反映,电驴连接不到服务器的情况,今天小编就跟大家讲讲电驴服务器怎么连接,让你轻松下载到自己需要的资源。eMule连接服务器教程步骤一:在电驴服务器界面右边的“从URL更新server.met”字样下边的小框里输入“”,然后点击“更新”,下载新的服务器列表即可(使用的网址不要emule.org.cn提供的)步骤二:解决kad网络无法连接1…

    2022年6月18日
    171
  • 二维数组a[3][4]_树状数组的算法原理

    二维数组a[3][4]_树状数组的算法原理原题链接堆栈是一种经典的后进先出的线性结构,相关的操作主要有“入栈”(在堆栈顶插入一个元素)和“出栈”(将栈顶元素返回并从堆栈中删除)。本题要求你实现另一个附加的操作:“取中值”——即返回所有堆栈中元素键值的中值。给定 N 个元素,如果 N 是偶数,则中值定义为第 N/2 小元;若是奇数,则为第 (N+1)/2 小元。输入格式:输入的第一行是正整数 N(≤10​5​​ )。随后 N 行,每行给出一句指令,为以下 3 种之一:Push keyPopPeekMedian其中 key 是不超过

    2022年8月8日
    4
  • 服务器命令里面怎么删除文件,scp删除服务器文件命令

    服务器命令里面怎么删除文件,scp删除服务器文件命令scp删除服务器文件命令内容精选换一换您需要将编译后的可执行文件拷贝到目标服务器,并构造相关输入数据,从而运行工程。对于本文档的应用示例,查看$HOME/tools/projects/Custom_Engine/main.cpp中所需输入数据如下所示:以ascend用户登录DDK所在服务器。执行如下命令,拷贝后的目录结构请见表1。cp-r$HOME/tools/proje当创建文件系统后,您…

    2022年8月22日
    19
  • FPGA的图像处理算法

    FPGA的图像处理算法下面简要分析了FPGA技术,包括FPGA技术原理和技术特点等,随后介绍一下FPGA的图像处理系统算法的实现,包括存储模块、运算单元、控制模块以及数据传输模块等内容。智能机器人、多媒体已经计算机的诞生都离不开数字图象处理技术,随着计算机智能化图像处理技术的不断发展,几乎所有领域当中都有数字图象技术的身影。例如军事、公共安全、工业、航天航空、卫星遥感以及生命科学等各种领域。因此对图象处理…

    2022年5月17日
    38

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号