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)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • nginx和apache的区别[通俗易懂]

    nginx和apache的区别[通俗易懂]简单的说apachehttpd和nginx都是web服务器,但两者适应的场景不同,也就是两者专注于解决不同的问题。apachehttpd:稳定、对动态请求处理强,但同时高并发时性能较弱,耗费资源多。nginx:高并发处理能力强、擅长处理静态请求、反向代理、均衡负载。在这篇文章详细列出了apache与nginx的13个异同点,下面我们来一一分析其原理。1、nginx相对于apache的优点:轻量级,同样起web服务,比apache占用更少的内存及资源,抗并发,nginx处理请求是异

    2022年6月13日
    40
  • 俞敏洪沉默,新东方落泪

    俞敏洪沉默,新东方落泪据传,早些年以新东方三位创始人创业为主线故事,风靡一时的电影《中国合伙人》开拍前,剧组曾向电影男主角的原型人物俞敏洪,提出了友好交流的请求。俞敏洪提出最大的意见是:可不可以别把我拍得这么“土鳖”?几十年来,号称农村出身的寒门子弟俞敏洪,其身份发生了重大变化。在公开场合里,他对自己的身世表露出深深的自卑。另一方面,他又被誉为中国留学教父,俨然成为一个农村“凤凰男”逆袭成精英阶级的典型代表。当然,俞敏洪还是新东方的创始人,中国商业洪流里响当当的传奇。“我吃一碗兰州拉面都很开心”。可就是这样一个人,对财

    2022年9月13日
    0
  • leetocde-416分割等和子集(01背包)

    leetocde-416分割等和子集(01背包)原题链接给定一个只包含正整数的非空数组。是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。注意:每个数组中的元素不会超过 100数组的大小不会超过 200示例 1:输入: [1, 5, 11, 5]输出: true解释: 数组可以分割成 [1, 5, 5] 和 [11]. 示例 2:输入: [1, 2, 3, 5]输出: false解释: 数组不能分割成两个元素和相等的子集.题解先看和如果式奇数,返回false,否则除以2,然后看是否能够用拼凑出整合处于

    2022年8月8日
    1
  • 澳男星“雷神”发布健身App 好友与妻子齐助阵

    澳男星“雷神”发布健身App 好友与妻子齐助阵

    2021年6月29日
    148
  • 2021的vmware12激活码【在线注册码/序列号/破解码】

    2021的vmware12激活码【在线注册码/序列号/破解码】,https://javaforall.net/100143.html。详细ieda激活码不妨到全栈程序员必看教程网一起来了解一下吧!

    2022年3月20日
    61
  • vue生成时间戳_hive时间戳转换日期

    vue生成时间戳_hive时间戳转换日期1.首先定义好一个工具类:2.在对应的文件中引入该文件:3.局部注册过滤器:

    2022年10月21日
    0

发表回复

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

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