本文将讲解NTP的代码实现和调试过程的一些记录。 首先,进行NTP报文结构体的构建。
//宏定义
#define NTP_TIMESTAMP_DELTA 2208988800ull //number of seconds between 1900 and 1970,1900-1970的时间差
#define SEC_TIME_ZONE + (8*60*60) //Beijing,GMT+8, 时区差
typedef struct
{
uint8_t li_vn_mode; // Eight bits. li, vn, and mode.
// li. Two bits. Leap indicator.
// vn. Three bits. Version number of the protocol.
// mode. Three bits. Client will pick mode 3 for client.
uint8_t stratum; // Eight bits. Stratum level of the local clock.
uint8_t poll; // Eight bits. Maximum interval between successive messages.
uint8_t precision; // Eight bits. Precision of the local clock.
uint32_t rootDelay; // 32 bits. Total round trip delay time.
uint32_t rootDispersion; // 32 bits. Max error aloud from primary clock source.
uint32_t refId; // 32 bits. Reference clock identifier.
uint32_t refTm_s; // 32 bits. Reference time-stamp seconds.
uint32_t refTm_f; // 32 bits. Reference time-stamp fraction of a second.
uint32_t origTm_s; // 32 bits. Originate time-stamp seconds.
uint32_t origTm_f; // 32 bits. Originate time-stamp fraction of a second.
uint32_t rxTm_s; // 32 bits. Received time-stamp seconds.
uint32_t rxTm_f; // 32 bits. Received time-stamp fraction of a second.
uint32_t txTm_s; // 32 bits and the most important field the client cares about. Transmit time-stamp seconds.
uint32_t txTm_f; // 32 bits. Transmit time-stamp fraction of a second.
} ntp_packet; // Total: 48 bytes.
接着进行NTP报文数据的发送、接收、接收数据处理、时间打印。
void NTP_Func(void)
{
uint8_t addr[4]={
192,168,4,9};//本地模拟开启的一个服务器
uint8_t i;
uint8_t buf[48];
uint16_t port=0;
uint16_t *Pport=&port;
uint32_t local_timestamp;
ntp_packet packet ;
struct tm * Net_time;
uint8_t NTP_Data[48]; //48字节的报文
NTP_Data[0]=0xa3;
//00100011, 0xa3,100 版本4
//00011011, 0x1b,011 版本3
//00010011, 0x13,010 版本2
//00001011, 0x0b,001 版本1
//后面分别发送了4个不同版本,都可以收到数据。
for(i=1;i<48;i++)NTP_Data[i]=0;//剩余的47字节为0
socket(3,Sn_MR_UDP,8080,0x00);//本地打开一个socket3,协议是UDP协议,端口是8080
sendto(3,NTP_Data,48,addr,123);//向addr的123端口发送报文,NTP使用的是UDP和123端口。
recvfrom(3,buf,48,addr,Pport);//接收返回的数据,48字节
//其中,sendto和recvfrom是w5500网口芯片自带的socket.c中的函数
//注意:UDP模式发送和接收使用sendto和recvfrom函数,TCP模式使用send和recv函数,当时调试时不知道,使用send和recv函数一直无法收到数据,卡了好久。
packet.txTm_s = buf[40]<<24 | buf[40+1]<<16|buf[40+2]<<8 |buf[40+3];//由于本文的时间精度要求不高,故自己用服务器返回的时间作为对时的时间,并未用公式:时间差offset=((T2-T1)+(T3-T4))/2。而是用T3作为对时基准时间。
local_timestamp = packet.txTm_s - NTP_TIMESTAMP_DELTA;//减去1970和1900的差值
local_timestamp +=SEC_TIME_ZONE; //加上北京的时间差,GMT+8
Net_time = localtime(&local_timestamp); //秒数转换位标准时间,下一篇将详细讲解Time.h中的时间转换函数
printf("%d-%d-%d %d:%d:%d\r\n",(Net_time->tm_year)+1900, (Net_time->tm_mon)+1, Net_time->tm_mday, Net_time->tm_hour,Net_time->tm_min,Net_time->tm_sec); //打印出时间
}
在主函数中调用void NTP_Func(void)打印出收到的时间。收到的时间如下:
自己电脑的123端口的打开方式见链接:https://zhidao.baidu.com/question/520907069418583765.html?qbl=relate_question_6&word=%D4%F5%C3%B4%CD%A8%B9%FD123%B6%CB%BF%DA%B2%E9%D1%AF%CA%B1%BC%E4&qq-pf-to=pcqq.c2c 打开123端口后,可以用网络调试助手小软件进行NTP的数据模拟,如下。
报文的第一个字节分别改为0x1b,0x13,0x0b,也是可以收到服务器返回的报文,说明UDP向老版本兼容。
NTP实例的源码:https://download.csdn.net/download/u014470361/10234803
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/183316.html原文链接:https://javaforall.cn