打印

获取sntp服务器时间同步本地时间

[复制链接]
404|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
哈金|  楼主 | 2018-7-6 10:24 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
分享一下之前项目用到的同步网络时间的程序给大家,本例需要用到socket,要操作系统的支持,大家可以在 探索者F4 资料盘(A盘)\4,程序源码\3,扩展例程\2,LWIP扩展例程\网络实验10 NETCONN_WEBserver实验 的基础下测试。
rtc.h文件增加了如下结构体:
struct rtc_time
{
        u16 year;
        u8 month;
        u8 day;
        u8 week;
        u8 hour;
        u8 min;
        u8 sec;
        u8 ampm;
};

函数 void RTC_Get_Date(u8 *year,u8 *month,u8 *date,u8 *week);
改为 void RTC_Get_Date(u16 *year,u8 *month,u8 *date,u8 *week);
这些可以看着办,我主要是方便使用。

以下为代码,实现获取sntp服务器的时间,并同步更新本地时间(说明一下,我对时间精度要求不高,所以直接用服务器向客户发时间戳的时间来更新本地时间,经测试,误差小于一秒,这主要看网络状态和服务器的位置,我用的是深圳阿里云,我在广州):
[mw_shl_code=c,true]#include <string.h>  
#include <time.h>
#include "lwip/sockets.h"
#include "lwip/inet.h"
#include <netdb.h>  
#include "sntp.h"  
#include "rtc.h"

#define bzero(a, b)             memset(a, 0, b)

#define JAN_1970    2208988676UL+28701        /* 1970 - 1900 in seconds */  
#define NTP_SERVER_NAME "120.24.166.46"    //深圳阿里云
#define NTP_PORT    123  

typedef struct   
{  
    unsigned char LiVnMode;  
    unsigned char Stratum;  
    unsigned char Poll;  
    unsigned char Precision;  
    long int RootDelay;  
    long int RootDispersion;  
    char RefID[4];  
    long int RefTimeInt;  
    long int RefTimeFraction;  
    long int OriTimeInt;  
    long int OriTimeFraction;  
    long int RecvTimeInt;  
    long int RecvTimeFraction;  
    long int TranTimeInt;  
    long int TranTimeFraction;  
}STNP_Header;  
  

//获取sntp服务器的时间
int GetNTPTime(STNP_Header *H_SNTP)  
{  
    int sockfd=0;  
    struct sockaddr_in server;  
                fd_set set;   
    struct timeval timeout;  
     
               
    bzero((void*)H_SNTP, sizeof(STNP_Header));  //清零
    H_SNTP->LiVnMode = 0x1b;  //设置NTP报文格式,LI=0:无警告;  VN=3:NTP的版本号为3;  Mode=3:客户;
               
                //设置要连接的对方的IP地址和端口等属性
                bzero(&server,sizeof(server));//初始化结构体
                server.sin_family = AF_INET;    //设置地址家族
                server.sin_port = htons(NTP_PORT);  //设置端口
                if(inet_aton(NTP_SERVER_NAME,&server.sin_addr) <= 0)//设置地址
      printf("inet_pton error\r\n");
        
    sockfd = socket(AF_INET, SOCK_DGRAM, 0);  //创建一个UDP socket
    if(sockfd<0)  
    {  
        printf("sockfd error!\r\n");  
        return -1;  
    }  
                //发送数据
    if(sendto(sockfd, (void*)H_SNTP, sizeof(STNP_Header), 0, (struct sockaddr*)&server, sizeof(server))<0)  
    {  
        printf("sendto error!\r\n");  
        return -1;  
    }  
      
    FD_ZERO(&set);  //清除描述词组set的全部位
    FD_SET(sockfd, &set);//设置描述词组set中相关fd的位
    timeout.tv_sec = 5;  //等待超时时间
    timeout.tv_usec = 0;  
      
    if( select(sockfd+1, &set, NULL, NULL, &timeout) <= 0 )  
                {
                                printf("select wait timeout!\r\n");  
        return -1;  
                }
    if(recv(sockfd, (void*)H_SNTP, sizeof(STNP_Header), 0)<0)  
                {
                                printf("recv error!\r\n");
        return -1;  
                }
      
    close(sockfd);  
    return 0;  
}  

//同步时间
//返回0:成功,-1:失败
int SYNC_Time(void)  
{  
    STNP_Header HeaderSNTP;  
    time_t t1;  
                struct timeval tv;  
                struct rtc_time st;
                struct tm *time;
        
                //获取sntp服务器数据
    printf("sync time from %s\n",NTP_SERVER_NAME);  
    if(GetNTPTime(&HeaderSNTP)<0)  
        return -1;         
                //从1900年1月1号0时0分0秒到服务器向客户发时间戳的时间,单位:秒
    t1 = ntohl(HeaderSNTP.TranTimeInt);  
                printf("t1:%u\r\n",t1);
                //减去1900年至1970年的时间
    tv.tv_sec=t1-JAN_1970;  
    printf("UTC:%s\r\n", ctime((const unsigned int *)&tv.tv_sec));  
               
                //把从1970-1-1零点零分到当前时间系统所偏移的秒数时间转换为日历时间
                //获得的tm结构体的时间,是已经进行过时区转化为本地时间,年份加上1900,月份加上1
                time=localtime((const unsigned int *)&tv.tv_sec);
                printf("sntp:%u-%u-%u,%u:%u:%u,星期%d\r\n",(time->tm_year)+1900,(time->tm_mon)+1,time->tm_mday,time->tm_hour,time->tm_min,time->tm_sec,time->tm_wday);
               
                //获取rtc时间
                RTC_Get_Time(&st.hour,&st.min,&st.sec,&st.ampm);
                RTC_Get_Date(&st.year,&st.month,&st.day,&st.week);
                st.year=st.year+2000;
                printf("rtc1:%d-%d-%d,%d:%d:%d\r\n",st.year,st.month,st.day,st.hour,st.min,st.sec);
                //时间相差超过1分钟就更新时间
                if(st.year!=(time->tm_year)+1900 | st.month!=(time->tm_mon)+1 | st.day!=time->tm_mday)
                {
                        RTC_Set_Date((time->tm_year)+1900-2000,(time->tm_mon)+1,time->tm_mday,time->tm_wday);
                        printf("RTC set date!\r\n");
                }
                if(st.hour!=time->tm_hour | st.min!=time->tm_min)
                {
                        if(time->tm_hour<12) st.ampm=0;
                        else st.ampm=1;
                        RTC_Set_Time(time->tm_hour,time->tm_min,time->tm_sec,st.ampm);
                        printf("RTC set time!\r\n");
                }
                RTC_Get_Time(&st.hour,&st.min,&st.sec,&st.ampm);
                RTC_Get_Date(&st.year,&st.month,&st.day,&st.week);
                st.year=st.year+2000;
                printf("rtc2:%d-%d-%d,%d:%d:%d\r\n",st.year,st.month,st.day,st.hour,st.min,st.sec);
               
    return 0;  
}  
[/mw_shl_code]






























网络实验10 NETCONN_WEBserver实验.rar







2016-8-11 09:26 上传

点击文件名下载附件

使用特权

评论回复

相关帖子

发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

432

主题

433

帖子

1

粉丝